From 4b82094ef023a2788edd7d357cf4bf6dda6554f1 Mon Sep 17 00:00:00 2001 From: grgr-dkrk <40130327+grgr-dkrk@users.noreply.github.com> Date: Mon, 25 Oct 2021 17:32:50 +0900 Subject: [PATCH 1/6] feat: add accessibilityLabelledBy --- Libraries/Components/View/ViewPropTypes.js | 7 +++++++ Libraries/Text/Text.js | 2 ++ Libraries/Text/TextProps.js | 2 ++ .../react/uimanager/BaseViewManager.java | 6 ++++++ .../uimanager/BaseViewManagerAdapter.java | 3 +++ .../uimanager/ReactAccessibilityDelegate.java | 19 +++++++++++++++++++ .../interfaces/BaseViewManagerDelegate.java | 3 +++ .../interfaces/BaseViewManagerInterface.java | 2 ++ .../react/uimanager/interfaces/ViewProps.java | 1 + .../main/res/views/uimanager/values/ids.xml | 3 +++ .../Accessibility/AccessibilityExample.js | 18 ++++++++++++++++++ 11 files changed, 66 insertions(+) diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index 497d94cff18b..50d6d24149a0 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -432,6 +432,13 @@ export type ViewProps = $ReadOnly<{| */ accessibilityActions?: ?$ReadOnlyArray, + /** + * Specifies the nativeID of the associated label text. When the assistive technology focuses on the component with this props, the text is read aloud. + * + * @platform android + */ + accessibilityLabelledBy?: ?string, + /** * Views that are only used to layout their children or otherwise don't draw * anything may be automatically removed from the native hierarchy as an diff --git a/Libraries/Text/Text.js b/Libraries/Text/Text.js index 22474f0711fc..439ab56e91e2 100644 --- a/Libraries/Text/Text.js +++ b/Libraries/Text/Text.js @@ -29,6 +29,7 @@ const Text: React.AbstractComponent< > = React.forwardRef((props: TextProps, forwardedRef) => { const { accessible, + accessibilityLabelledBy, allowFontScaling, ellipsizeMode, onLongPress, @@ -179,6 +180,7 @@ const Text: React.AbstractComponent< numberOfLines={numberOfLines} selectionColor={selectionColor} style={style} + accessibilityLabelledBy={accessibilityLabelledBy} ref={forwardedRef} /> diff --git a/Libraries/Text/TextProps.js b/Libraries/Text/TextProps.js index 3942a5998cd3..0e41456b3b46 100644 --- a/Libraries/Text/TextProps.js +++ b/Libraries/Text/TextProps.js @@ -199,4 +199,6 @@ export type TextProps = $ReadOnly<{| * See https://reactnative.dev/docs/text.html#supperhighlighting */ suppressHighlighting?: ?boolean, + + accessibilityLabelledBy?: ?string, |}>; diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java index 25579c4c292f..2eb01a164eed 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java @@ -137,6 +137,12 @@ public void setNativeId(@NonNull T view, @Nullable String nativeId) { ReactFindViewUtil.notifyViewRendered(view); } + @Override + @ReactProp(name = ViewProps.ACCESSIBILITY_LABELLED_BY) + public void setAccessibilityLabelledBy(@NonNull T view, String nativeId) { + view.setTag(R.id.labelled_by, nativeId); + } + @Override @ReactProp(name = ViewProps.ACCESSIBILITY_LABEL) public void setAccessibilityLabel(@NonNull T view, @Nullable String accessibilityLabel) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManagerAdapter.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManagerAdapter.java index c0e21dece66f..3826f059dd77 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManagerAdapter.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManagerAdapter.java @@ -64,6 +64,9 @@ public void setImportantForAccessibility( @Override public void setNativeId(@NonNull T view, String nativeId) {} + @Override + public void setAccessibilityLabelledBy(@NonNull T view, String nativeId) {} + @Override public void setOpacity(@NonNull T view, float opacity) {} diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java index 9436df80d3f0..52a4b49933ca 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java @@ -36,6 +36,7 @@ import com.facebook.react.uimanager.events.Event; import com.facebook.react.uimanager.events.EventDispatcher; import java.util.HashMap; +import com.facebook.react.uimanager.util.ReactFindViewUtil; /** * Utility class that handles the addition of a "role" for accessibility to either a View or @@ -200,6 +201,24 @@ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCo setRole(info, accessibilityRole, host.getContext()); } + final Object accessibilityLabelledBy = host.getTag(R.id.labelled_by); + if (accessibilityLabelledBy != null) { + ReactFindViewUtil.findView( + host.getRootView(), + new ReactFindViewUtil.OnViewFoundListener() { + @Override + public String getNativeId() { + return (String) accessibilityLabelledBy; + } + + @Override + public void onViewFound(View view) { + info.setLabeledBy(view); + } + } + ); + } + // state is changeable. final ReadableMap accessibilityState = (ReadableMap) host.getTag(R.id.accessibility_state); if (accessibilityState != null) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/interfaces/BaseViewManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/interfaces/BaseViewManagerDelegate.java index 1598b578877b..893e7bf1cab0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/interfaces/BaseViewManagerDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/interfaces/BaseViewManagerDelegate.java @@ -84,6 +84,9 @@ public void setProperty(T view, String propName, @Nullable Object value) { case ViewProps.NATIVE_ID: mViewManager.setNativeId(view, (String) value); break; + case ViewProps.ACCESSIBILITY_LABELLED_BY: + mViewManager.setAccessibilityLabelledBy(view, (String) value); + break; case ViewProps.OPACITY: mViewManager.setOpacity(view, value == null ? 1.0f : ((Double) value).floatValue()); break; diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/interfaces/BaseViewManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/interfaces/BaseViewManagerInterface.java index 5423eeedd91a..5fadf7ad89d6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/interfaces/BaseViewManagerInterface.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/interfaces/BaseViewManagerInterface.java @@ -49,6 +49,8 @@ public interface BaseViewManagerInterface { void setNativeId(T view, @Nullable String nativeId); + void setAccessibilityLabelledBy(T view, @Nullable String nativeId); + void setOpacity(T view, float opacity); void setRenderToHardwareTexture(T view, boolean useHWTexture); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/interfaces/ViewProps.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/interfaces/ViewProps.java index 61151919cc0d..c7087b2baa5b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/interfaces/ViewProps.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/interfaces/ViewProps.java @@ -152,6 +152,7 @@ public class ViewProps { public static final String ACCESSIBILITY_STATE = "accessibilityState"; public static final String ACCESSIBILITY_ACTIONS = "accessibilityActions"; public static final String ACCESSIBILITY_VALUE = "accessibilityValue"; + public static final String ACCESSIBILITY_LABELLED_BY = "accessibilityLabelledBy"; public static final String IMPORTANT_FOR_ACCESSIBILITY = "importantForAccessibility"; // DEPRECATED diff --git a/ReactAndroid/src/main/res/views/uimanager/values/ids.xml b/ReactAndroid/src/main/res/views/uimanager/values/ids.xml index 6886defd4692..b552bd5eaa7f 100644 --- a/ReactAndroid/src/main/res/views/uimanager/values/ids.xml +++ b/ReactAndroid/src/main/res/views/uimanager/values/ids.xml @@ -27,4 +27,7 @@ + + + diff --git a/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js b/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js index 6133080a4adf..9973ee190870 100644 --- a/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js +++ b/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js @@ -192,6 +192,24 @@ class AccessibilityExample extends React.Component<{}> { Accessible view with label, hint, role, and state + + + + Mail Address + + First Name + + + ); } From 8f710ad2917e340d83ddf0a433cbeca03104c35c Mon Sep 17 00:00:00 2001 From: grgr-dkrk <40130327+grgr-dkrk@users.noreply.github.com> Date: Mon, 25 Oct 2021 18:20:15 +0900 Subject: [PATCH 2/6] chore: fix lint error --- Libraries/Components/View/ViewPropTypes.js | 2 +- .../uimanager/ReactAccessibilityDelegate.java | 27 +++++++++---------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index 50d6d24149a0..4ef28110b146 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -434,7 +434,7 @@ export type ViewProps = $ReadOnly<{| /** * Specifies the nativeID of the associated label text. When the assistive technology focuses on the component with this props, the text is read aloud. - * + * * @platform android */ accessibilityLabelledBy?: ?string, diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java index 52a4b49933ca..ef13f20b00f4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java @@ -35,8 +35,8 @@ import com.facebook.react.bridge.WritableMap; import com.facebook.react.uimanager.events.Event; import com.facebook.react.uimanager.events.EventDispatcher; -import java.util.HashMap; import com.facebook.react.uimanager.util.ReactFindViewUtil; +import java.util.HashMap; /** * Utility class that handles the addition of a "role" for accessibility to either a View or @@ -203,20 +203,19 @@ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCo final Object accessibilityLabelledBy = host.getTag(R.id.labelled_by); if (accessibilityLabelledBy != null) { - ReactFindViewUtil.findView( - host.getRootView(), - new ReactFindViewUtil.OnViewFoundListener() { - @Override - public String getNativeId() { - return (String) accessibilityLabelledBy; - } - - @Override - public void onViewFound(View view) { - info.setLabeledBy(view); - } + ReactFindViewUtil.findView( + host.getRootView(), + new ReactFindViewUtil.OnViewFoundListener() { + @Override + public String getNativeId() { + return (String) accessibilityLabelledBy; + } + + @Override + public void onViewFound(View view) { + info.setLabeledBy(view); } - ); + }); } // state is changeable. From ea3e7740d1d2af31dc9bf5a111d96af79454f486 Mon Sep 17 00:00:00 2001 From: grgr-dkrk <40130327+grgr-dkrk@users.noreply.github.com> Date: Mon, 25 Oct 2021 22:53:23 +0900 Subject: [PATCH 3/6] chore: change findView from async to sync --- .../uimanager/ReactAccessibilityDelegate.java | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java index ef13f20b00f4..c8befc9ad26c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java @@ -192,6 +192,8 @@ public void handleMessage(Message msg) { }; } + @Nullable View mAccessibilityLabelledBy; + @Override public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) { super.onInitializeAccessibilityNodeInfo(host, info); @@ -203,19 +205,11 @@ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCo final Object accessibilityLabelledBy = host.getTag(R.id.labelled_by); if (accessibilityLabelledBy != null) { - ReactFindViewUtil.findView( - host.getRootView(), - new ReactFindViewUtil.OnViewFoundListener() { - @Override - public String getNativeId() { - return (String) accessibilityLabelledBy; - } - - @Override - public void onViewFound(View view) { - info.setLabeledBy(view); - } - }); + mAccessibilityLabelledBy = + ReactFindViewUtil.findView(host.getRootView(), (String) accessibilityLabelledBy); + if (mAccessibilityLabelledBy != null) { + info.setLabeledBy(mAccessibilityLabelledBy); + } } // state is changeable. From 771ee40edf2a9c5a1cee933a169d634656386924 Mon Sep 17 00:00:00 2001 From: grgr-dkrk <40130327+grgr-dkrk@users.noreply.github.com> Date: Tue, 26 Oct 2021 20:24:40 +0900 Subject: [PATCH 4/6] chore: remove accessibilityLabelledBy props from Text --- Libraries/Text/Text.js | 2 -- Libraries/Text/TextProps.js | 2 -- 2 files changed, 4 deletions(-) diff --git a/Libraries/Text/Text.js b/Libraries/Text/Text.js index 439ab56e91e2..22474f0711fc 100644 --- a/Libraries/Text/Text.js +++ b/Libraries/Text/Text.js @@ -29,7 +29,6 @@ const Text: React.AbstractComponent< > = React.forwardRef((props: TextProps, forwardedRef) => { const { accessible, - accessibilityLabelledBy, allowFontScaling, ellipsizeMode, onLongPress, @@ -180,7 +179,6 @@ const Text: React.AbstractComponent< numberOfLines={numberOfLines} selectionColor={selectionColor} style={style} - accessibilityLabelledBy={accessibilityLabelledBy} ref={forwardedRef} /> diff --git a/Libraries/Text/TextProps.js b/Libraries/Text/TextProps.js index 0e41456b3b46..3942a5998cd3 100644 --- a/Libraries/Text/TextProps.js +++ b/Libraries/Text/TextProps.js @@ -199,6 +199,4 @@ export type TextProps = $ReadOnly<{| * See https://reactnative.dev/docs/text.html#supperhighlighting */ suppressHighlighting?: ?boolean, - - accessibilityLabelledBy?: ?string, |}>; From 11dc16481074b6d49fdc5ca253ec20aac04d1b89 Mon Sep 17 00:00:00 2001 From: grgr-dkrk <40130327+grgr-dkrk@users.noreply.github.com> Date: Tue, 26 Oct 2021 23:52:59 +0900 Subject: [PATCH 5/6] fix: Changed `accessibilityLabelledBy` to accept array as well --- Libraries/Components/View/ViewPropTypes.js | 2 +- .../facebook/react/uimanager/BaseViewManager.java | 13 +++++++++++-- .../react/uimanager/BaseViewManagerAdapter.java | 3 ++- .../interfaces/BaseViewManagerDelegate.java | 3 ++- .../interfaces/BaseViewManagerInterface.java | 3 ++- .../examples/Accessibility/AccessibilityExample.js | 2 +- 6 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index 4ef28110b146..58a2dad2230f 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -437,7 +437,7 @@ export type ViewProps = $ReadOnly<{| * * @platform android */ - accessibilityLabelledBy?: ?string, + accessibilityLabelledBy?: ?string | ?Array, /** * Views that are only used to layout their children or otherwise don't draw diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java index 2eb01a164eed..0f6aa8029d6c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java @@ -139,8 +139,17 @@ public void setNativeId(@NonNull T view, @Nullable String nativeId) { @Override @ReactProp(name = ViewProps.ACCESSIBILITY_LABELLED_BY) - public void setAccessibilityLabelledBy(@NonNull T view, String nativeId) { - view.setTag(R.id.labelled_by, nativeId); + public void setAccessibilityLabelledBy(@NonNull T view, @Nullable Dynamic nativeId) { + if (nativeId.isNull()) { + return; + } + if (nativeId.getType() == ReadableType.String) { + view.setTag(R.id.labelled_by, nativeId.asString()); + } else if (nativeId.getType() == ReadableType.Array) { + // On Android, this takes a single View as labeledBy. If an array is specified, set the first + // element in the tag. + view.setTag(R.id.labelled_by, nativeId.asArray().getString(0)); + } } @Override diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManagerAdapter.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManagerAdapter.java index 3826f059dd77..de9423e6f8bd 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManagerAdapter.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManagerAdapter.java @@ -10,6 +10,7 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; @@ -65,7 +66,7 @@ public void setImportantForAccessibility( public void setNativeId(@NonNull T view, String nativeId) {} @Override - public void setAccessibilityLabelledBy(@NonNull T view, String nativeId) {} + public void setAccessibilityLabelledBy(@NonNull T view, Dynamic nativeId) {} @Override public void setOpacity(@NonNull T view, float opacity) {} diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/interfaces/BaseViewManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/interfaces/BaseViewManagerDelegate.java index 893e7bf1cab0..8d1ac8584d5e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/interfaces/BaseViewManagerDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/interfaces/BaseViewManagerDelegate.java @@ -10,6 +10,7 @@ import android.view.View; import androidx.annotation.Nullable; import com.facebook.react.bridge.ColorPropConverter; +import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.yoga.YogaConstants; @@ -85,7 +86,7 @@ public void setProperty(T view, String propName, @Nullable Object value) { mViewManager.setNativeId(view, (String) value); break; case ViewProps.ACCESSIBILITY_LABELLED_BY: - mViewManager.setAccessibilityLabelledBy(view, (String) value); + mViewManager.setAccessibilityLabelledBy(view, (Dynamic) value); break; case ViewProps.OPACITY: mViewManager.setOpacity(view, value == null ? 1.0f : ((Double) value).floatValue()); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/interfaces/BaseViewManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/interfaces/BaseViewManagerInterface.java index 5fadf7ad89d6..629cae7e8ebb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/interfaces/BaseViewManagerInterface.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/interfaces/BaseViewManagerInterface.java @@ -9,6 +9,7 @@ import android.view.View; import androidx.annotation.Nullable; +import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; @@ -49,7 +50,7 @@ public interface BaseViewManagerInterface { void setNativeId(T view, @Nullable String nativeId); - void setAccessibilityLabelledBy(T view, @Nullable String nativeId); + void setAccessibilityLabelledBy(T view, @Nullable Dynamic nativeId); void setOpacity(T view, float opacity); diff --git a/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js b/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js index 9973ee190870..9353e5eb524c 100644 --- a/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js +++ b/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js @@ -204,7 +204,7 @@ class AccessibilityExample extends React.Component<{}> { First Name From 1282770e3538caaa45379bc5ed18cab48d603638 Mon Sep 17 00:00:00 2001 From: grgr-dkrk <40130327+grgr-dkrk@users.noreply.github.com> Date: Tue, 26 Oct 2021 23:57:51 +0900 Subject: [PATCH 6/6] fix: example for lint --- .../rn-tester/js/examples/Accessibility/AccessibilityExample.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js b/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js index 9353e5eb524c..12e7bd929862 100644 --- a/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js +++ b/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js @@ -204,7 +204,7 @@ class AccessibilityExample extends React.Component<{}> { First Name