diff --git a/Libraries/Components/View/ReactNativeViewAttributes.js b/Libraries/Components/View/ReactNativeViewAttributes.js index 3a769ca5e..ab12b9fdc 100644 --- a/Libraries/Components/View/ReactNativeViewAttributes.js +++ b/Libraries/Components/View/ReactNativeViewAttributes.js @@ -18,6 +18,7 @@ var ReactNativeViewAttributes = {}; ReactNativeViewAttributes.UIView = { pointerEvents: true, accessible: true, + accessibilityActions: true, accessibilityLabel: true, accessibilityComponentType: true, accessibilityLiveRegion: true, @@ -28,6 +29,7 @@ ReactNativeViewAttributes.UIView = { renderToHardwareTextureAndroid: true, shouldRasterizeIOS: true, onLayout: true, + onAccessibilityAction: true, onAccessibilityTap: true, onMagicTap: true, collapsable: true, diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index d6510a388..5c639dfde 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -49,11 +49,13 @@ export type ViewLayoutEvent = { export type ViewProps = { accessible?: bool, accessibilityLabel?: React$PropType$Primitive, + accessibilityActions?: Array, accessibilityComponentType?: AccessibilityComponentType, accessibilityLiveRegion?: 'none' | 'polite' | 'assertive', importantForAccessibility?: 'auto'| 'yes'| 'no'| 'no-hide-descendants', accessibilityTraits?: AccessibilityTrait | Array, accessibilityViewIsModal?: bool, + onAccessibilityAction?: Function, onAccessibilityTap?: Function, onMagicTap?: Function, testID?: string, @@ -99,6 +101,13 @@ module.exports = { */ accessibilityLabel: PropTypes.node, + /** + * Provides an array of custom actions available for accessibility. + * + * @platform ios + */ + accessibilityActions: PropTypes.arrayOf(PropTypes.string), + /** * Indicates to accessibility services to treat UI component like a * native one. Works for Android only. @@ -165,6 +174,14 @@ module.exports = { */ accessibilityViewIsModal: PropTypes.bool, + /** + * When `accessible` is true, the system will try to invoke this function + * when the user performs an accessibility custom action. + * + * @platform ios + */ + onAccessibilityAction: PropTypes.func, + /** * When `accessible` is true, the system will try to invoke this function * when the user performs accessibility tap gesture. diff --git a/React/Views/RCTView.h b/React/Views/RCTView.h index 5c223987d..fd0071f93 100644 --- a/React/Views/RCTView.h +++ b/React/Views/RCTView.h @@ -23,9 +23,15 @@ /** * Accessibility event handlers */ +@property (nonatomic, copy) RCTDirectEventBlock onAccessibilityAction; @property (nonatomic, copy) RCTDirectEventBlock onAccessibilityTap; @property (nonatomic, copy) RCTDirectEventBlock onMagicTap; +/** + * Accessibility properties + */ +@property (nonatomic, copy) NSArray *accessibilityActions; + /** * Used to control how touch events are processed. */ diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m index 6fdc0873f..9a1aacc74 100644 --- a/React/Views/RCTView.m +++ b/React/Views/RCTView.m @@ -156,6 +156,36 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:unused) return RCTRecursiveAccessibilityLabel(self); } +- (NSArray *)accessibilityCustomActions +{ + if (!_accessibilityActions.count) { + return nil; + } + + NSMutableArray *actions = [NSMutableArray array]; + for (NSString *action in _accessibilityActions) { + [actions addObject:[[UIAccessibilityCustomAction alloc] initWithName:action + target:self + selector:@selector(didActivateAccessibilityCustomAction:)]]; + } + + return [actions copy]; +} + +- (BOOL)didActivateAccessibilityCustomAction:(UIAccessibilityCustomAction *)action +{ + if (!_onAccessibilityAction) { + return NO; + } + + _onAccessibilityAction(@{ + @"action": action.name, + @"target": self.reactTag + }); + + return YES; +} + - (void)setPointerEvents:(RCTPointerEvents)pointerEvents { _pointerEvents = pointerEvents; diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index a6b3725bb..2aba8a754 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -119,9 +119,11 @@ RCT_EXPORT_VIEW_PROPERTY(nativeID, NSString) // Acessibility related properties RCT_REMAP_VIEW_PROPERTY(accessible, reactAccessibilityElement.isAccessibilityElement, BOOL) +RCT_REMAP_VIEW_PROPERTY(accessibilityActions, reactAccessibilityElement.accessibilityActions, NSString) RCT_REMAP_VIEW_PROPERTY(accessibilityLabel, reactAccessibilityElement.accessibilityLabel, NSString) RCT_REMAP_VIEW_PROPERTY(accessibilityTraits, reactAccessibilityElement.accessibilityTraits, UIAccessibilityTraits) RCT_REMAP_VIEW_PROPERTY(accessibilityViewIsModal, reactAccessibilityElement.accessibilityViewIsModal, BOOL) +RCT_REMAP_VIEW_PROPERTY(onAccessibilityAction, reactAccessibilityElement.onAccessibilityAction, RCTDirectEventBlock) RCT_REMAP_VIEW_PROPERTY(onAccessibilityTap, reactAccessibilityElement.onAccessibilityTap, RCTDirectEventBlock) RCT_REMAP_VIEW_PROPERTY(onMagicTap, reactAccessibilityElement.onMagicTap, RCTDirectEventBlock) RCT_REMAP_VIEW_PROPERTY(testID, reactAccessibilityElement.accessibilityIdentifier, NSString)