Generalization of isInAParentText context

Summary:
Currently `isInAParentText` context works as imaginary `isInAAncestorText` context (not like a real `isInAParentText`).
Let's imagine we have hierarchy like:
`View -> Text -> Text* -> View* -> Text* -> Text* -> View*`
With current implementation all nodes marked with asterisk have `isInAParentText` context, which is incorrect (because some of them actually in View context).

With the new implemetations it will work like this:
`View -> Text -> Text* -> View* -> Text -> Text* -> View*`
So, only nodes which have <Text> (or <TextInput>) as a parent will have `isInAParentText` context.

This change allows to select proper `Text` vs. `VirtualText` component in cases where <Text> and <View> components can interleave each other.

Reviewed By: sahrens

Differential Revision: D6690495

fbshipit-source-id: f7c59b23d0eaf68a1d08036b858d99c9547f7878
This commit is contained in:
Valentin Shergin 2018-01-14 19:32:33 -08:00 committed by Facebook Github Bot
parent 95320626e1
commit 52648326e6
5 changed files with 56 additions and 25 deletions

View File

@ -31,6 +31,7 @@ const TimerMixin = require('react-timer-mixin');
const TouchableWithoutFeedback = require('TouchableWithoutFeedback'); const TouchableWithoutFeedback = require('TouchableWithoutFeedback');
const UIManager = require('UIManager'); const UIManager = require('UIManager');
const ViewPropTypes = require('ViewPropTypes'); const ViewPropTypes = require('ViewPropTypes');
const {ViewContextTypes} = require('ViewContext');
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
* found when Flow v0.54 was deployed. To see the error delete this comment and * found when Flow v0.54 was deployed. To see the error delete this comment and
@ -48,6 +49,8 @@ const onlyMultiline = {
children: true, children: true,
}; };
import type {ViewChildContext} from 'ViewContext';
if (Platform.OS === 'android') { if (Platform.OS === 'android') {
var AndroidTextInput = requireNativeComponent('AndroidTextInput', null); var AndroidTextInput = requireNativeComponent('AndroidTextInput', null);
} else if (Platform.OS === 'ios') { } else if (Platform.OS === 'ios') {
@ -612,11 +615,6 @@ const TextInput = createReactClass({
); );
}, },
contextTypes: {
onFocusRequested: PropTypes.func,
focusEmitter: PropTypes.instanceOf(EventEmitter),
},
_inputRef: (undefined: any), _inputRef: (undefined: any),
_focusSubscription: (undefined: ?Function), _focusSubscription: (undefined: ?Function),
_lastNativeText: (undefined: ?string), _lastNativeText: (undefined: ?string),
@ -652,12 +650,18 @@ const TextInput = createReactClass({
} }
}, },
getChildContext: function(): Object { getChildContext(): ViewChildContext {
return {isInAParentText: true}; return {
isInAParentText: true,
};
}, },
childContextTypes: { childContextTypes: ViewContextTypes,
isInAParentText: PropTypes.bool,
contextTypes: {
...ViewContextTypes,
onFocusRequested: PropTypes.func,
focusEmitter: PropTypes.instanceOf(EventEmitter),
}, },
/** /**

View File

@ -14,17 +14,18 @@
const NativeMethodsMixin = require('NativeMethodsMixin'); const NativeMethodsMixin = require('NativeMethodsMixin');
const Platform = require('Platform'); const Platform = require('Platform');
const PropTypes = require('prop-types');
const React = require('React'); const React = require('React');
const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes'); const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
const ReactNativeViewAttributes = require('ReactNativeViewAttributes'); const ReactNativeViewAttributes = require('ReactNativeViewAttributes');
const ViewPropTypes = require('ViewPropTypes'); const ViewPropTypes = require('ViewPropTypes');
const {ViewContextTypes} = require('ViewContext');
const createReactClass = require('create-react-class'); const createReactClass = require('create-react-class');
const invariant = require('fbjs/lib/invariant'); const invariant = require('fbjs/lib/invariant');
const requireNativeComponent = require('requireNativeComponent'); const requireNativeComponent = require('requireNativeComponent');
import type {ViewProps} from 'ViewPropTypes'; import type {ViewProps} from 'ViewPropTypes';
import type {ViewChildContext} from 'ViewContext';
export type Props = ViewProps; export type Props = ViewProps;
@ -56,8 +57,12 @@ const View = createReactClass({
validAttributes: ReactNativeViewAttributes.RCTView, validAttributes: ReactNativeViewAttributes.RCTView,
}, },
contextTypes: { childContextTypes: ViewContextTypes,
isInAParentText: PropTypes.bool,
getChildContext(): ViewChildContext {
return {
isInAParentText: false,
};
}, },
render() { render() {

View File

@ -0,0 +1,23 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ViewContext
* @flow
* @format
*/
'use strict';
const PropTypes = require('prop-types');
export type ViewChildContext = {|
+isInAParentText: boolean,
|};
export const ViewContextTypes = {
isInAParentText: PropTypes.bool,
};

View File

@ -22,17 +22,17 @@ var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var Set = require('Set'); var Set = require('Set');
var StyleSheet = require('StyleSheet'); var StyleSheet = require('StyleSheet');
var StyleSheetPropType = require('StyleSheetPropType'); var StyleSheetPropType = require('StyleSheetPropType');
var View = require('View');
var ViewPropTypes = require('ViewPropTypes'); var ViewPropTypes = require('ViewPropTypes');
var ViewStylePropTypes = require('ViewStylePropTypes'); var ViewStylePropTypes = require('ViewStylePropTypes');
var createReactClass = require('create-react-class'); var createReactClass = require('create-react-class');
var filterObject = require('fbjs/lib/filterObject');
var flattenStyle = require('flattenStyle'); var flattenStyle = require('flattenStyle');
var merge = require('merge'); var merge = require('merge');
var requireNativeComponent = require('requireNativeComponent'); var requireNativeComponent = require('requireNativeComponent');
var resolveAssetSource = require('resolveAssetSource'); var resolveAssetSource = require('resolveAssetSource');
const {ViewContextTypes} = require('ViewContext');
var {ImageLoader} = NativeModules; var {ImageLoader} = NativeModules;
let _requestId = 1; let _requestId = 1;
@ -261,9 +261,7 @@ var Image = createReactClass({
validAttributes: ReactNativeViewAttributes.RCTView, validAttributes: ReactNativeViewAttributes.RCTView,
}, },
contextTypes: { contextTypes: ViewContextTypes,
isInAParentText: PropTypes.bool,
},
render: function() { render: function() {
const source = resolveAssetSource(this.props.source); const source = resolveAssetSource(this.props.source);

View File

@ -26,9 +26,12 @@ const createReactClass = require('create-react-class');
const requireNativeComponent = require('requireNativeComponent'); const requireNativeComponent = require('requireNativeComponent');
const mergeFast = require('mergeFast'); const mergeFast = require('mergeFast');
const processColor = require('processColor'); const processColor = require('processColor');
const {ViewContextTypes} = require('ViewContext');
const stylePropType = StyleSheetPropType(TextStylePropTypes); const stylePropType = StyleSheetPropType(TextStylePropTypes);
import type {ViewChildContext} from 'ViewContext';
/** /**
* A React component for displaying text. * A React component for displaying text.
* *
@ -401,15 +404,13 @@ const Text = createReactClass({
}); });
}, },
mixins: [NativeMethodsMixin], mixins: [NativeMethodsMixin],
getChildContext(): Object { getChildContext(): ViewChildContext {
return {isInAParentText: true}; return {
}, isInAParentText: true,
childContextTypes: { };
isInAParentText: PropTypes.bool,
},
contextTypes: {
isInAParentText: PropTypes.bool,
}, },
childContextTypes: ViewContextTypes,
contextTypes: ViewContextTypes,
/** /**
* Only assigned if touch is needed. * Only assigned if touch is needed.
*/ */