From 4fe63292bdf1c239b421641e1ac25391b9786a76 Mon Sep 17 00:00:00 2001 From: Omeid Date: Mon, 14 Nov 2016 14:04:42 +1100 Subject: [PATCH 1/3] ios:UIViewManager: Export accessibilityElementsHidden UIKit accessibilityElementsHidden property is similar to Android's importantForAccessibility and very important for creating a good accessible experience by hidden off the screen and invisible elements/vies from VoiceOver and other assestive technologies. This commit also improves accessiblity of Navigation Experimental CardStack by marking inactive (off screen) scenes invsible for ios VoiceOver and Android's Talkback. Closes #9725 --- Libraries/Components/View/View.js | 11 +++++- .../NavigationExperimental/NavigationCard.js | 2 ++ React/Views/RCTViewManager.m | 34 ++++++------------- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/Libraries/Components/View/View.js b/Libraries/Components/View/View.js index 2f7e21c78b14f3..efdc858d070681 100644 --- a/Libraries/Components/View/View.js +++ b/Libraries/Components/View/View.js @@ -189,10 +189,19 @@ const View = React.createClass({ 'assertive', ]), + /** + * Controls whether the accessibility elements contained within this view are hidden. + * Works for iOS Only. For Android, See [importantForAccessibility](#importantforaccessibility) + * + * @platform ios + */ + + accessibilityElementsHidden: PropTypes.bool, + /** * Controls how view is important for accessibility which is if it * fires accessibility events and if it is reported to accessibility services - * that query the screen. Works for Android only. + * that query the screen. Works for Android only. For iOS see [importantForAccessibility](#accessibilityElementsHidden) * * Possible values: * diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js b/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js index e2f42fed3ed1ee..6d9f65afe3099a 100644 --- a/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js +++ b/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js @@ -100,6 +100,8 @@ class NavigationCard extends React.Component { {...viewPanHandlers} pointerEvents={pointerEvents} ref={this.props.onComponentRef} + accessibilityElementsHidden={!props.scene.isActive} // iOS + importantForAccessibility={props.scene.isActive ? 'yes' : 'no-hide-descendants'} // Android style={[styles.main, viewStyle]}> {renderScene(props)} diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index 249cfeca47d110..6689c32fe65128 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -20,10 +20,6 @@ #import "RCTView.h" #import "UIView+React.h" -#if TARGET_OS_TV -#import "RCTTVView.h" -#endif - @implementation RCTConvert(UIAccessibilityTraits) RCT_MULTI_ENUM_CONVERTER(UIAccessibilityTraits, (@{ @@ -61,11 +57,7 @@ - (dispatch_queue_t)methodQueue - (UIView *)view { -#if TARGET_OS_TV - return [RCTTVView new]; -#else return [RCTView new]; -#endif } - (RCTShadowView *)shadowView @@ -106,13 +98,7 @@ - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(__unused NSDictio #pragma mark - View properties -#if TARGET_OS_TV -// Apple TV properties -RCT_EXPORT_VIEW_PROPERTY(isTVSelectable, BOOL) -RCT_EXPORT_VIEW_PROPERTY(hasTVPreferredFocus, BOOL) -RCT_EXPORT_VIEW_PROPERTY(tvParallaxProperties, NSDictionary) -#endif - +RCT_EXPORT_VIEW_PROPERTY(accessibilityElementsHidden, BOOL) RCT_EXPORT_VIEW_PROPERTY(accessibilityLabel, NSString) RCT_EXPORT_VIEW_PROPERTY(accessibilityTraits, UIAccessibilityTraits) RCT_EXPORT_VIEW_PROPERTY(backgroundColor, UIColor) @@ -124,10 +110,10 @@ - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(__unused NSDictio RCT_REMAP_VIEW_PROPERTY(shadowOffset, layer.shadowOffset, CGSize) RCT_REMAP_VIEW_PROPERTY(shadowOpacity, layer.shadowOpacity, float) RCT_REMAP_VIEW_PROPERTY(shadowRadius, layer.shadowRadius, CGFloat) -RCT_CUSTOM_VIEW_PROPERTY(overflow, YGOverflow, RCTView) +RCT_CUSTOM_VIEW_PROPERTY(overflow, CSSOverflow, RCTView) { if (json) { - view.clipsToBounds = [RCTConvert YGOverflow:json] != YGOverflowVisible; + view.clipsToBounds = [RCTConvert CSSOverflow:json] != CSSOverflowVisible; } else { view.clipsToBounds = defaultView.clipsToBounds; } @@ -303,15 +289,15 @@ - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(__unused NSDictio RCT_EXPORT_SHADOW_PROPERTY(flexGrow, float) RCT_EXPORT_SHADOW_PROPERTY(flexShrink, float) RCT_EXPORT_SHADOW_PROPERTY(flexBasis, float) -RCT_EXPORT_SHADOW_PROPERTY(flexDirection, YGFlexDirection) -RCT_EXPORT_SHADOW_PROPERTY(flexWrap, YGWrap) -RCT_EXPORT_SHADOW_PROPERTY(justifyContent, YGJustify) -RCT_EXPORT_SHADOW_PROPERTY(alignItems, YGAlign) -RCT_EXPORT_SHADOW_PROPERTY(alignSelf, YGAlign) -RCT_EXPORT_SHADOW_PROPERTY(position, YGPositionType) +RCT_EXPORT_SHADOW_PROPERTY(flexDirection, CSSFlexDirection) +RCT_EXPORT_SHADOW_PROPERTY(flexWrap, CSSWrap) +RCT_EXPORT_SHADOW_PROPERTY(justifyContent, CSSJustify) +RCT_EXPORT_SHADOW_PROPERTY(alignItems, CSSAlign) +RCT_EXPORT_SHADOW_PROPERTY(alignSelf, CSSAlign) +RCT_EXPORT_SHADOW_PROPERTY(position, CSSPositionType) RCT_EXPORT_SHADOW_PROPERTY(aspectRatio, float) -RCT_EXPORT_SHADOW_PROPERTY(overflow, YGOverflow) +RCT_EXPORT_SHADOW_PROPERTY(overflow, CSSOverflow) RCT_EXPORT_SHADOW_PROPERTY(onLayout, RCTDirectEventBlock) From a05612e9f018fd28b2cdae0f265441095e4acfd7 Mon Sep 17 00:00:00 2001 From: Omeid Date: Wed, 16 Nov 2016 15:52:49 +1100 Subject: [PATCH 2/3] Components:View: Android support for accessibilityElementsHidden This commit adds Android support for View's `accessibilityElementsHidden` prop and marks Android only's `importantForAccessibility` as deprecated. This commit also includes the relevant improvements for NavigationExperimental NavigationCard. --- Libraries/Components/View/View.js | 40 +++++-------------- .../NavigationExperimental/NavigationCard.js | 3 +- React/Views/RCTViewManager.m | 33 ++++++++++----- 3 files changed, 36 insertions(+), 40 deletions(-) diff --git a/Libraries/Components/View/View.js b/Libraries/Components/View/View.js index efdc858d070681..a474542ecefd41 100644 --- a/Libraries/Components/View/View.js +++ b/Libraries/Components/View/View.js @@ -26,6 +26,7 @@ if (Platform.isTVOS) { TVViewPropTypes = require('TVViewPropTypes'); } +const deprecatedPropType = require('deprecatedPropType'); const requireNativeComponent = require('requireNativeComponent'); const PropTypes = React.PropTypes; @@ -191,38 +192,19 @@ const View = React.createClass({ /** * Controls whether the accessibility elements contained within this view are hidden. - * Works for iOS Only. For Android, See [importantForAccessibility](#importantforaccessibility) - * - * @platform ios + * Use this property to indicate whatever the view should be reported to accessibility services that query the screen. */ - accessibilityElementsHidden: PropTypes.bool, - /** - * Controls how view is important for accessibility which is if it - * fires accessibility events and if it is reported to accessibility services - * that query the screen. Works for Android only. For iOS see [importantForAccessibility](#accessibilityElementsHidden) - * - * Possible values: - * - * - `'auto'` - The system determines whether the view is important for accessibility - - * default (recommended). - * - `'yes'` - The view is important for accessibility. - * - `'no'` - The view is not important for accessibility. - * - `'no-hide-descendants'` - The view is not important for accessibility, - * nor are any of its descendant views. - * - * See the [Android `importantForAccessibility` docs](http://developer.android.com/reference/android/R.attr.html#importantForAccessibility) - * for reference. - * - * @platform android - */ - importantForAccessibility: PropTypes.oneOf([ - 'auto', - 'yes', - 'no', - 'no-hide-descendants', - ]), + importantForAccessibility: deprecatedPropType( + PropTypes.oneOf([ + 'auto', + 'yes', + 'no', + 'no-hide-descendants', + ]), + 'Use the `accessibilityElementsHidden` prop instead.' + ), /** * Provides additional traits to screen reader. By default no traits are diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js b/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js index 6d9f65afe3099a..b764ea19b12f8c 100644 --- a/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js +++ b/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js @@ -100,8 +100,7 @@ class NavigationCard extends React.Component { {...viewPanHandlers} pointerEvents={pointerEvents} ref={this.props.onComponentRef} - accessibilityElementsHidden={!props.scene.isActive} // iOS - importantForAccessibility={props.scene.isActive ? 'yes' : 'no-hide-descendants'} // Android + accessibilityElementsHidden={!props.scene.isActive} style={[styles.main, viewStyle]}> {renderScene(props)} diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index 6689c32fe65128..3252cc9b7c061a 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -20,6 +20,10 @@ #import "RCTView.h" #import "UIView+React.h" +#if TARGET_OS_TV +#import "RCTTVView.h" +#endif + @implementation RCTConvert(UIAccessibilityTraits) RCT_MULTI_ENUM_CONVERTER(UIAccessibilityTraits, (@{ @@ -57,7 +61,11 @@ - (dispatch_queue_t)methodQueue - (UIView *)view { +#if TARGET_OS_TV + return [RCTTVView new]; +#else return [RCTView new]; +#endif } - (RCTShadowView *)shadowView @@ -98,6 +106,13 @@ - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(__unused NSDictio #pragma mark - View properties +#if TARGET_OS_TV +// Apple TV properties +RCT_EXPORT_VIEW_PROPERTY(isTVSelectable, BOOL) +RCT_EXPORT_VIEW_PROPERTY(hasTVPreferredFocus, BOOL) +RCT_EXPORT_VIEW_PROPERTY(tvParallaxProperties, NSDictionary) +#endif + RCT_EXPORT_VIEW_PROPERTY(accessibilityElementsHidden, BOOL) RCT_EXPORT_VIEW_PROPERTY(accessibilityLabel, NSString) RCT_EXPORT_VIEW_PROPERTY(accessibilityTraits, UIAccessibilityTraits) @@ -110,10 +125,10 @@ - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(__unused NSDictio RCT_REMAP_VIEW_PROPERTY(shadowOffset, layer.shadowOffset, CGSize) RCT_REMAP_VIEW_PROPERTY(shadowOpacity, layer.shadowOpacity, float) RCT_REMAP_VIEW_PROPERTY(shadowRadius, layer.shadowRadius, CGFloat) -RCT_CUSTOM_VIEW_PROPERTY(overflow, CSSOverflow, RCTView) +RCT_CUSTOM_VIEW_PROPERTY(overflow, YGOverflow, RCTView) { if (json) { - view.clipsToBounds = [RCTConvert CSSOverflow:json] != CSSOverflowVisible; + view.clipsToBounds = [RCTConvert YGOverflow:json] != YGOverflowVisible; } else { view.clipsToBounds = defaultView.clipsToBounds; } @@ -289,15 +304,15 @@ - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(__unused NSDictio RCT_EXPORT_SHADOW_PROPERTY(flexGrow, float) RCT_EXPORT_SHADOW_PROPERTY(flexShrink, float) RCT_EXPORT_SHADOW_PROPERTY(flexBasis, float) -RCT_EXPORT_SHADOW_PROPERTY(flexDirection, CSSFlexDirection) -RCT_EXPORT_SHADOW_PROPERTY(flexWrap, CSSWrap) -RCT_EXPORT_SHADOW_PROPERTY(justifyContent, CSSJustify) -RCT_EXPORT_SHADOW_PROPERTY(alignItems, CSSAlign) -RCT_EXPORT_SHADOW_PROPERTY(alignSelf, CSSAlign) -RCT_EXPORT_SHADOW_PROPERTY(position, CSSPositionType) +RCT_EXPORT_SHADOW_PROPERTY(flexDirection, YGFlexDirection) +RCT_EXPORT_SHADOW_PROPERTY(flexWrap, YGWrap) +RCT_EXPORT_SHADOW_PROPERTY(justifyContent, YGJustify) +RCT_EXPORT_SHADOW_PROPERTY(alignItems, YGAlign) +RCT_EXPORT_SHADOW_PROPERTY(alignSelf, YGAlign) +RCT_EXPORT_SHADOW_PROPERTY(position, YGPositionType) RCT_EXPORT_SHADOW_PROPERTY(aspectRatio, float) -RCT_EXPORT_SHADOW_PROPERTY(overflow, CSSOverflow) +RCT_EXPORT_SHADOW_PROPERTY(overflow, YGOverflow) RCT_EXPORT_SHADOW_PROPERTY(onLayout, RCTDirectEventBlock) From 926118150cb9c1b3f0119126cc3759002aef47c2 Mon Sep 17 00:00:00 2001 From: Martin Konicek Date: Wed, 23 Nov 2016 12:00:06 +0000 Subject: [PATCH 3/3] Wording --- Libraries/Components/View/View.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Libraries/Components/View/View.js b/Libraries/Components/View/View.js index a474542ecefd41..ecdb0ea84ce995 100644 --- a/Libraries/Components/View/View.js +++ b/Libraries/Components/View/View.js @@ -191,8 +191,14 @@ const View = React.createClass({ ]), /** - * Controls whether the accessibility elements contained within this view are hidden. - * Use this property to indicate whatever the view should be reported to accessibility services that query the screen. + * Controls whether the accessibility elements contained within this view are hidden + * from accessibility services that query the screen. + * + * - If `true`, this View and all accessibility elements contained within it are hidden + * from accessibility services. + * - If `false`, this view is visible to accessibility services. + * - The default value is `null` which means the OS decides which elements are important + * for accessibility. */ accessibilityElementsHidden: PropTypes.bool,