AccessibilityWrapper.ios.js 2.55 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
import React from 'react';
import PropTypes from 'prop-types';
import {
  NativeModules,
  ViewProps,
  ViewPropTypes,
  findNodeHandle,
  requireNativeComponent,
  Platform,
  View,
} from 'react-native';

const {RNAccessibilityWrapperManager} = NativeModules;

const RNAccessibilityWrapper = requireNativeComponent('RNAccessibilityWrapper');

const AccessibilityWrapperPropTypes = {
  ...ViewPropTypes,
  fieldsRefs: PropTypes.arrayOf(
    PropTypes.shape({
      current: PropTypes.object,
    }),
  ),
};

class AccessibilityWrapperIOS extends React.Component {
  static propTypes = AccessibilityWrapperPropTypes;

  ref = React.createRef();

  componentDidMount() {
    if (this.props.fieldsRefs) {
      this.setAccessibilityFields(
        this.props.fieldsRefs.map(ref => ref.current),
      );
    }
  }
  componentDidUpdate() {
    if (this.props.fieldsRefs) {
      this.setAccessibilityFields(
        this.props.fieldsRefs.map(ref => ref.current),
      );
    }
  }

  setAccessibilityFields = (fields = []) => {
    const fieldTags =
      fields && fields.map(component => component && findNodeHandle(component));
    return RNAccessibilityWrapperManager.setAccessibilityFields(
      findNodeHandle(this.ref.current),
      fieldTags,
    );
  };

  render() {
    return <RNAccessibilityWrapper {...this.props} ref={this.ref} />;
  }
}

const AccessibilityWrapperAndroid = ({fieldsRefs, ...props}) => (
  <View {...props} />
);
AccessibilityWrapperAndroid.propTypes = AccessibilityWrapperPropTypes;

/**
 * The AccessibilityWrapper component allows you to adjust the behaviour of the native platform
 * when it comes to accessibility. Using this component you can tell the native platform to
 * group all subviews together for accessibility purposes (since it's not always done by
 * default), and you can even override the focus order of subviews
 *
 * @example
 *  export default class App extends Component<{}> {
 *    fooRef = React.createRef<Text>();
 *    barRef = React.createRef<Text>();
 *    bazRef = React.createRef<Text>();
 *
 *    public render() {
 *      return (
 *        <AccessibilityWrapper fieldsRefs={[
 *          this.barRef,
 *          this.fooRef,
 *          this.bazRef,
 *        ]}>
 *          <SafeAreaView>
 *            <Text ref={this.fooRef}>Foo</Text>
 *            <Text ref={this.barRef}>Bar</Text>
 *            <Text ref={this.bazRef}>Baz</Text>
 *          </SafeAreaView>
 *        </AccessibilityWrapper>
 *      );
 *    }
 *  }
 */
export default Platform.select({
  ios: AccessibilityWrapperIOS,
  android: AccessibilityWrapperAndroid,
});