RN: Replace `context.isInAParentText` w/ React.createContext
Reviewed By: sahrens Differential Revision: D7895382 fbshipit-source-id: 4affcecd147b8e8c506e0d94f223bac3e6dfdf66
This commit is contained in:
parent
5d4c542c58
commit
e1339bc183
|
@ -20,6 +20,7 @@ const PropTypes = require('prop-types');
|
||||||
const ReactNative = require('ReactNative');
|
const ReactNative = require('ReactNative');
|
||||||
const StyleSheet = require('StyleSheet');
|
const StyleSheet = require('StyleSheet');
|
||||||
const Text = require('Text');
|
const Text = require('Text');
|
||||||
|
const TextAncestor = require('TextAncestor');
|
||||||
const TextInputState = require('TextInputState');
|
const TextInputState = require('TextInputState');
|
||||||
/* $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
|
||||||
|
@ -28,7 +29,6 @@ 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');
|
|
||||||
|
|
||||||
const emptyFunction = require('fbjs/lib/emptyFunction');
|
const emptyFunction = require('fbjs/lib/emptyFunction');
|
||||||
const invariant = require('fbjs/lib/invariant');
|
const invariant = require('fbjs/lib/invariant');
|
||||||
|
@ -47,8 +47,6 @@ const onlyMultiline = {
|
||||||
children: true,
|
children: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
import type {ViewChildContext} from 'ViewContext';
|
|
||||||
|
|
||||||
if (Platform.OS === 'android') {
|
if (Platform.OS === 'android') {
|
||||||
AndroidTextInput = requireNativeComponent('AndroidTextInput', null);
|
AndroidTextInput = requireNativeComponent('AndroidTextInput', null);
|
||||||
} else if (Platform.OS === 'ios') {
|
} else if (Platform.OS === 'ios') {
|
||||||
|
@ -701,16 +699,7 @@ const TextInput = createReactClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getChildContext(): ViewChildContext {
|
|
||||||
return {
|
|
||||||
isInAParentText: true,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
childContextTypes: ViewContextTypes,
|
|
||||||
|
|
||||||
contextTypes: {
|
contextTypes: {
|
||||||
...ViewContextTypes,
|
|
||||||
onFocusRequested: PropTypes.func,
|
onFocusRequested: PropTypes.func,
|
||||||
focusEmitter: PropTypes.instanceOf(EventEmitter),
|
focusEmitter: PropTypes.instanceOf(EventEmitter),
|
||||||
},
|
},
|
||||||
|
@ -723,13 +712,17 @@ const TextInput = createReactClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
|
let textInput;
|
||||||
if (Platform.OS === 'ios') {
|
if (Platform.OS === 'ios') {
|
||||||
return UIManager.RCTVirtualText
|
textInput = UIManager.RCTVirtualText
|
||||||
? this._renderIOS()
|
? this._renderIOS()
|
||||||
: this._renderIOSLegacy();
|
: this._renderIOSLegacy();
|
||||||
} else if (Platform.OS === 'android') {
|
} else if (Platform.OS === 'android') {
|
||||||
return this._renderAndroid();
|
textInput = this._renderAndroid();
|
||||||
}
|
}
|
||||||
|
return (
|
||||||
|
<TextAncestor.Provider value={true}>{textInput}</TextAncestor.Provider>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
_getText: function(): ?string {
|
_getText: function(): ?string {
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* @flow
|
* @flow
|
||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const Platform = require('Platform');
|
const Platform = require('Platform');
|
||||||
|
@ -14,13 +15,13 @@ const React = require('React');
|
||||||
const ReactNative = require('ReactNative');
|
const ReactNative = require('ReactNative');
|
||||||
const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
|
const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
|
||||||
const ReactNativeViewAttributes = require('ReactNativeViewAttributes');
|
const ReactNativeViewAttributes = require('ReactNativeViewAttributes');
|
||||||
|
const TextAncestor = require('TextAncestor');
|
||||||
const ViewPropTypes = require('ViewPropTypes');
|
const ViewPropTypes = require('ViewPropTypes');
|
||||||
const {ViewContextTypes} = require('ViewContext');
|
|
||||||
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;
|
||||||
|
|
||||||
|
@ -33,30 +34,31 @@ export type Props = ViewProps;
|
||||||
*/
|
*/
|
||||||
class View extends ReactNative.NativeComponent<Props> {
|
class View extends ReactNative.NativeComponent<Props> {
|
||||||
static propTypes = ViewPropTypes;
|
static propTypes = ViewPropTypes;
|
||||||
static childContextTypes = ViewContextTypes;
|
|
||||||
|
|
||||||
viewConfig = {
|
viewConfig = {
|
||||||
uiViewClassName: 'RCTView',
|
uiViewClassName: 'RCTView',
|
||||||
validAttributes: ReactNativeViewAttributes.RCTView,
|
validAttributes: ReactNativeViewAttributes.RCTView,
|
||||||
};
|
};
|
||||||
|
|
||||||
getChildContext(): ViewChildContext {
|
/**
|
||||||
return {
|
* WARNING: This method will not be used in production mode as in that mode we
|
||||||
isInAParentText: false,
|
* replace wrapper component View with generated native wrapper RCTView. Avoid
|
||||||
};
|
* adding functionality this component that you'd want to be available in both
|
||||||
}
|
* dev and prod modes.
|
||||||
|
*/
|
||||||
render() {
|
render() {
|
||||||
invariant(
|
return (
|
||||||
!(this.context.isInAParentText && Platform.OS === 'android'),
|
<TextAncestor.Consumer>
|
||||||
'Nesting of <View> within <Text> is not supported on Android.',
|
{hasTextAncestor => {
|
||||||
|
// TODO: Change iOS to behave the same as Android.
|
||||||
|
invariant(
|
||||||
|
!hasTextAncestor || Platform.OS !== 'android',
|
||||||
|
'Nesting of <View> within <Text> is not supported on Android.',
|
||||||
|
);
|
||||||
|
return <RCTView {...this.props} />;
|
||||||
|
}}
|
||||||
|
</TextAncestor.Consumer>
|
||||||
);
|
);
|
||||||
|
|
||||||
// WARNING: This method will not be used in production mode as in that mode we
|
|
||||||
// replace wrapper component View with generated native wrapper RCTView. Avoid
|
|
||||||
// adding functionality this component that you'd want to be available in both
|
|
||||||
// dev and prod modes.
|
|
||||||
return <RCTView {...this.props} />;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* @flow
|
* @flow
|
||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var ImageResizeMode = require('ImageResizeMode');
|
var ImageResizeMode = require('ImageResizeMode');
|
||||||
|
@ -18,6 +19,7 @@ var PropTypes = require('prop-types');
|
||||||
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
|
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
|
||||||
var StyleSheet = require('StyleSheet');
|
var StyleSheet = require('StyleSheet');
|
||||||
var StyleSheetPropType = require('StyleSheetPropType');
|
var StyleSheetPropType = require('StyleSheetPropType');
|
||||||
|
const TextAncestor = require('TextAncestor');
|
||||||
var ViewPropTypes = require('ViewPropTypes');
|
var ViewPropTypes = require('ViewPropTypes');
|
||||||
|
|
||||||
var createReactClass = require('create-react-class');
|
var createReactClass = require('create-react-class');
|
||||||
|
@ -26,8 +28,6 @@ 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;
|
||||||
|
@ -202,8 +202,6 @@ var Image = createReactClass({
|
||||||
validAttributes: ReactNativeViewAttributes.RCTView,
|
validAttributes: ReactNativeViewAttributes.RCTView,
|
||||||
},
|
},
|
||||||
|
|
||||||
contextTypes: ViewContextTypes,
|
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
const source = resolveAssetSource(this.props.source);
|
const source = resolveAssetSource(this.props.source);
|
||||||
const defaultSource = resolveAssetSource(this.props.defaultSource);
|
const defaultSource = resolveAssetSource(this.props.defaultSource);
|
||||||
|
@ -236,42 +234,44 @@ var Image = createReactClass({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source && (source.uri || Array.isArray(source))) {
|
if (!source || (!source.uri && !Array.isArray(source))) {
|
||||||
let style;
|
return null;
|
||||||
let sources;
|
|
||||||
if (source.uri) {
|
|
||||||
const {width, height} = source;
|
|
||||||
style = flattenStyle([{width, height}, styles.base, this.props.style]);
|
|
||||||
sources = [{uri: source.uri}];
|
|
||||||
} else {
|
|
||||||
style = flattenStyle([styles.base, this.props.style]);
|
|
||||||
sources = source;
|
|
||||||
}
|
|
||||||
|
|
||||||
const {onLoadStart, onLoad, onLoadEnd, onError} = this.props;
|
|
||||||
const nativeProps = merge(this.props, {
|
|
||||||
style,
|
|
||||||
shouldNotifyLoadEvents: !!(
|
|
||||||
onLoadStart ||
|
|
||||||
onLoad ||
|
|
||||||
onLoadEnd ||
|
|
||||||
onError
|
|
||||||
),
|
|
||||||
src: sources,
|
|
||||||
headers: source.headers,
|
|
||||||
defaultSrc: defaultSource ? defaultSource.uri : null,
|
|
||||||
loadingIndicatorSrc: loadingIndicatorSource
|
|
||||||
? loadingIndicatorSource.uri
|
|
||||||
: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.context.isInAParentText) {
|
|
||||||
return <RCTTextInlineImage {...nativeProps} />;
|
|
||||||
} else {
|
|
||||||
return <RKImage {...nativeProps} />;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
let style;
|
||||||
|
let sources;
|
||||||
|
if (source.uri) {
|
||||||
|
const {width, height} = source;
|
||||||
|
style = flattenStyle([{width, height}, styles.base, this.props.style]);
|
||||||
|
sources = [{uri: source.uri}];
|
||||||
|
} else {
|
||||||
|
style = flattenStyle([styles.base, this.props.style]);
|
||||||
|
sources = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {onLoadStart, onLoad, onLoadEnd, onError} = this.props;
|
||||||
|
const nativeProps = merge(this.props, {
|
||||||
|
style,
|
||||||
|
shouldNotifyLoadEvents: !!(onLoadStart || onLoad || onLoadEnd || onError),
|
||||||
|
src: sources,
|
||||||
|
headers: source.headers,
|
||||||
|
defaultSrc: defaultSource ? defaultSource.uri : null,
|
||||||
|
loadingIndicatorSrc: loadingIndicatorSource
|
||||||
|
? loadingIndicatorSource.uri
|
||||||
|
: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TextAncestor.Consumer>
|
||||||
|
{hasTextAncestor =>
|
||||||
|
hasTextAncestor ? (
|
||||||
|
<RCTTextInlineImage {...nativeProps} />
|
||||||
|
) : (
|
||||||
|
<RKImage {...nativeProps} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</TextAncestor.Consumer>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
const React = require('React');
|
const React = require('React');
|
||||||
const ReactNative = require('ReactNative');
|
const ReactNative = require('ReactNative');
|
||||||
const ReactNativeViewAttributes = require('ReactNativeViewAttributes');
|
const ReactNativeViewAttributes = require('ReactNativeViewAttributes');
|
||||||
|
const TextAncestor = require('TextAncestor');
|
||||||
const TextPropTypes = require('TextPropTypes');
|
const TextPropTypes = require('TextPropTypes');
|
||||||
const Touchable = require('Touchable');
|
const Touchable = require('Touchable');
|
||||||
const UIManager = require('UIManager');
|
const UIManager = require('UIManager');
|
||||||
|
@ -19,11 +20,9 @@ const UIManager = require('UIManager');
|
||||||
const createReactNativeComponentClass = require('createReactNativeComponentClass');
|
const createReactNativeComponentClass = require('createReactNativeComponentClass');
|
||||||
const mergeFast = require('mergeFast');
|
const mergeFast = require('mergeFast');
|
||||||
const processColor = require('processColor');
|
const processColor = require('processColor');
|
||||||
const {ViewContextTypes} = require('ViewContext');
|
|
||||||
|
|
||||||
import type {PressEvent} from 'CoreEventTypes';
|
import type {PressEvent} from 'CoreEventTypes';
|
||||||
import type {TextProps} from 'TextProps';
|
import type {TextProps} from 'TextProps';
|
||||||
import type {ViewChildContext} from 'ViewContext';
|
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
isHighlighted: boolean,
|
isHighlighted: boolean,
|
||||||
|
@ -61,8 +60,6 @@ const viewConfig = {
|
||||||
*/
|
*/
|
||||||
class Text extends ReactNative.NativeComponent<TextProps, State> {
|
class Text extends ReactNative.NativeComponent<TextProps, State> {
|
||||||
static propTypes = TextPropTypes;
|
static propTypes = TextPropTypes;
|
||||||
static childContextTypes = ViewContextTypes;
|
|
||||||
static contextTypes = ViewContextTypes;
|
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
accessible: true,
|
accessible: true,
|
||||||
|
@ -76,12 +73,6 @@ class Text extends ReactNative.NativeComponent<TextProps, State> {
|
||||||
|
|
||||||
viewConfig = viewConfig;
|
viewConfig = viewConfig;
|
||||||
|
|
||||||
getChildContext(): ViewChildContext {
|
|
||||||
return {
|
|
||||||
isInAParentText: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
_handlers: ?Object;
|
_handlers: ?Object;
|
||||||
|
|
||||||
_hasPressHandler(): boolean {
|
_hasPressHandler(): boolean {
|
||||||
|
@ -215,11 +206,19 @@ class Text extends ReactNative.NativeComponent<TextProps, State> {
|
||||||
style: [this.props.style, {color: 'magenta'}],
|
style: [this.props.style, {color: 'magenta'}],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (this.context.isInAParentText) {
|
return (
|
||||||
return <RCTVirtualText {...newProps} />;
|
<TextAncestor.Consumer>
|
||||||
} else {
|
{hasTextAncestor =>
|
||||||
return <RCTText {...newProps} />;
|
hasTextAncestor ? (
|
||||||
}
|
<RCTVirtualText {...newProps} />
|
||||||
|
) : (
|
||||||
|
<TextAncestor.Provider value={true}>
|
||||||
|
<RCTText {...newProps} />
|
||||||
|
</TextAncestor.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</TextAncestor.Consumer>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,16 +7,12 @@
|
||||||
* @flow
|
* @flow
|
||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const PropTypes = require('prop-types');
|
const React = require('React');
|
||||||
|
|
||||||
export type ViewChildContext = {|
|
/**
|
||||||
+isInAParentText: boolean,
|
* Whether the current element is the descendant of a <Text> element.
|
||||||
|};
|
*/
|
||||||
|
module.exports = React.createContext(false);
|
||||||
module.exports = {
|
|
||||||
ViewContextTypes: {
|
|
||||||
isInAParentText: PropTypes.bool,
|
|
||||||
},
|
|
||||||
};
|
|
Loading…
Reference in New Issue