Skip to content

Commit

Permalink
Merge branch 'master' into image-resizemode-repeat-android
Browse files Browse the repository at this point in the history
  • Loading branch information
motiz88 authored Jan 16, 2018
2 parents 2651e74 + d0f7d4d commit d2cb163
Show file tree
Hide file tree
Showing 28 changed files with 838 additions and 587 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ Working on your first Pull Request? You can learn how from this free video serie

[**How to Contribute to an Open Source Project on GitHub**](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github)

We have a list of [beginner friendly issues](https://github.com/facebook/react-native/labels/Good%20First%20Task) to help you get your feet wet in the React Native codebase and familiar with our contribution process. This is a great place to get started.
We have a list of [beginner friendly issues](https://github.com/facebook/react-native/labels/Good%20first%20issue) to help you get your feet wet in the React Native codebase and familiar with our contribution process. This is a great place to get started.

### Proposing a change

Expand Down
177 changes: 129 additions & 48 deletions Libraries/Components/TextInput/TextInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*
* @providesModule TextInput
* @flow
* @format
*/
'use strict';

Expand All @@ -30,6 +31,7 @@ const TimerMixin = require('react-timer-mixin');
const TouchableWithoutFeedback = require('TouchableWithoutFeedback');
const UIManager = require('UIManager');
const ViewPropTypes = require('ViewPropTypes');
const {ViewContextTypes} = require('ViewContext');

/* $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
Expand All @@ -47,11 +49,19 @@ const onlyMultiline = {
children: true,
};

import type {ViewChildContext} from 'ViewContext';

if (Platform.OS === 'android') {
var AndroidTextInput = requireNativeComponent('AndroidTextInput', null);
} else if (Platform.OS === 'ios') {
var RCTMultilineTextInputView = requireNativeComponent('RCTMultilineTextInputView', null);
var RCTSinglelineTextInputView = requireNativeComponent('RCTSinglelineTextInputView', null);
var RCTMultilineTextInputView = requireNativeComponent(
'RCTMultilineTextInputView',
null,
);
var RCTSinglelineTextInputView = requireNativeComponent(
'RCTSinglelineTextInputView',
null,
);
}

type Event = Object;
Expand Down Expand Up @@ -279,11 +289,7 @@ const TextInput = createReactClass({
* Determines the color of the keyboard.
* @platform ios
*/
keyboardAppearance: PropTypes.oneOf([
'default',
'light',
'dark',
]),
keyboardAppearance: PropTypes.oneOf(['default', 'light', 'dark']),
/**
* Determines how the return key should look. On Android you can also use
* `returnKeyLabel`.
Expand Down Expand Up @@ -448,8 +454,8 @@ const TextInput = createReactClass({
*/
secureTextEntry: PropTypes.bool,
/**
* The highlight and cursor color of the text input.
*/
* The highlight and cursor color of the text input.
*/
selectionColor: ColorPropType,
/**
* An instance of `DocumentSelectionState`, this is some state that is responsible for
Expand Down Expand Up @@ -603,13 +609,10 @@ const TextInput = createReactClass({
* Returns `true` if the input is currently focused; `false` otherwise.
*/
isFocused: function(): boolean {
return TextInputState.currentlyFocusedField() ===
ReactNative.findNodeHandle(this._inputRef);
},

contextTypes: {
onFocusRequested: PropTypes.func,
focusEmitter: PropTypes.instanceOf(EventEmitter),
return (
TextInputState.currentlyFocusedField() ===
ReactNative.findNodeHandle(this._inputRef)
);
},

_inputRef: (undefined: any),
Expand All @@ -627,13 +630,13 @@ const TextInput = createReactClass({
}
this._focusSubscription = this.context.focusEmitter.addListener(
'focus',
(el) => {
el => {
if (this === el) {
this.requestAnimationFrame(this.focus);
} else if (this.isFocused()) {
this.blur();
}
}
},
);
if (this.props.autoFocus) {
this.context.onFocusRequested(this);
Expand All @@ -647,12 +650,18 @@ const TextInput = createReactClass({
}
},

getChildContext: function(): Object {
return {isInAParentText: true};
getChildContext(): ViewChildContext {
return {
isInAParentText: true,
};
},

childContextTypes: {
isInAParentText: PropTypes.bool
childContextTypes: ViewContextTypes,

contextTypes: {
...ViewContextTypes,
onFocusRequested: PropTypes.func,
focusEmitter: PropTypes.instanceOf(EventEmitter),
},

/**
Expand All @@ -664,48 +673,53 @@ const TextInput = createReactClass({

render: function() {
if (Platform.OS === 'ios') {
return this._renderIOS();
return UIManager.RCTVirtualText
? this._renderIOS()
: this._renderIOSLegacy();
} else if (Platform.OS === 'android') {
return this._renderAndroid();
}
},

_getText: function(): ?string {
return typeof this.props.value === 'string' ?
this.props.value :
(
typeof this.props.defaultValue === 'string' ?
this.props.defaultValue :
''
);
return typeof this.props.value === 'string'
? this.props.value
: typeof this.props.defaultValue === 'string'
? this.props.defaultValue
: '';
},

_setNativeRef: function(ref: any) {
this._inputRef = ref;
},

_renderIOS: function() {
_renderIOSLegacy: function() {
var textContainer;

var props = Object.assign({}, this.props);
props.style = [this.props.style];

if (props.selection && props.selection.end == null) {
props.selection = {start: props.selection.start, end: props.selection.start};
props.selection = {
start: props.selection.start,
end: props.selection.start,
};
}

if (!props.multiline) {
if (__DEV__) {
for (var propKey in onlyMultiline) {
if (props[propKey]) {
const error = new Error(
'TextInput prop `' + propKey + '` is only supported with multiline.'
'TextInput prop `' +
propKey +
'` is only supported with multiline.',
);
warning(false, '%s', error.stack);
}
}
}
textContainer =
textContainer = (
<RCTSinglelineTextInputView
ref={this._setNativeRef}
{...props}
Expand All @@ -715,23 +729,28 @@ const TextInput = createReactClass({
onSelectionChange={this._onSelectionChange}
onSelectionChangeShouldSetResponder={emptyFunction.thatReturnsTrue}
text={this._getText()}
/>;
/>
);
} else {
var children = props.children;
var childCount = 0;
React.Children.forEach(children, () => ++childCount);
invariant(
!(props.value && childCount),
'Cannot specify both value and children.'
'Cannot specify both value and children.',
);
if (childCount >= 1) {
children = <Text style={props.style} allowFontScaling={props.allowFontScaling}>{children}</Text>;
children = (
<Text style={props.style} allowFontScaling={props.allowFontScaling}>
{children}
</Text>
);
}
if (props.inputView) {
children = [children, props.inputView];
}
props.style.unshift(styles.multilineInput);
textContainer =
textContainer = (
<RCTMultilineTextInputView
ref={this._setNativeRef}
{...props}
Expand All @@ -746,9 +765,61 @@ const TextInput = createReactClass({
text={this._getText()}
dataDetectorTypes={this.props.dataDetectorTypes}
onScroll={this._onScroll}
/>;
/>
);
}

return (
<TouchableWithoutFeedback
onLayout={props.onLayout}
onPress={this._onPress}
rejectResponderTermination={true}
accessible={props.accessible}
accessibilityLabel={props.accessibilityLabel}
accessibilityTraits={props.accessibilityTraits}
nativeID={this.props.nativeID}
testID={props.testID}>
{textContainer}
</TouchableWithoutFeedback>
);
},

_renderIOS: function() {
var props = Object.assign({}, this.props);
props.style = [this.props.style];

if (props.selection && props.selection.end == null) {
props.selection = {
start: props.selection.start,
end: props.selection.start,
};
}

const RCTTextInputView = props.multiline
? RCTMultilineTextInputView
: RCTSinglelineTextInputView;

if (props.multiline) {
props.style.unshift(styles.multilineInput);
}

const textContainer = (
<RCTTextInputView
ref={this._setNativeRef}
{...props}
onFocus={this._onFocus}
onBlur={this._onBlur}
onChange={this._onChange}
onContentSizeChange={this.props.onContentSizeChange}
onSelectionChange={this._onSelectionChange}
onTextInput={this._onTextInput}
onSelectionChangeShouldSetResponder={emptyFunction.thatReturnsTrue}
text={this._getText()}
dataDetectorTypes={this.props.dataDetectorTypes}
onScroll={this._onScroll}
/>
);

return (
<TouchableWithoutFeedback
onLayout={props.onLayout}
Expand Down Expand Up @@ -779,17 +850,20 @@ const TextInput = createReactClass({
React.Children.forEach(children, () => ++childCount);
invariant(
!(this.props.value && childCount),
'Cannot specify both value and children.'
'Cannot specify both value and children.',
);
if (childCount > 1) {
children = <Text>{children}</Text>;
}

if (props.selection && props.selection.end == null) {
props.selection = {start: props.selection.start, end: props.selection.start};
props.selection = {
start: props.selection.start,
end: props.selection.start,
};
}

const textContainer =
const textContainer = (
<AndroidTextInput
ref={this._setNativeRef}
{...props}
Expand All @@ -804,7 +878,8 @@ const TextInput = createReactClass({
disableFullscreenUI={this.props.disableFullscreenUI}
textBreakStrategy={this.props.textBreakStrategy}
onScroll={this._onScroll}
/>;
/>
);

return (
<TouchableWithoutFeedback
Expand Down Expand Up @@ -875,22 +950,28 @@ const TextInput = createReactClass({
}
},

componentDidUpdate: function () {
componentDidUpdate: function() {
// This is necessary in case native updates the text and JS decides
// that the update should be ignored and we should stick with the value
// that we have in JS.
const nativeProps = {};

if (this._lastNativeText !== this.props.value && typeof this.props.value === 'string') {
if (
this._lastNativeText !== this.props.value &&
typeof this.props.value === 'string'
) {
nativeProps.text = this.props.value;
}

// Selection is also a controlled prop, if the native value doesn't match
// JS, update to the JS value.
const {selection} = this.props;
if (this._lastNativeSelection && selection &&
(this._lastNativeSelection.start !== selection.start ||
this._lastNativeSelection.end !== selection.end)) {
if (
this._lastNativeSelection &&
selection &&
(this._lastNativeSelection.start !== selection.start ||
this._lastNativeSelection.end !== selection.end)
) {
nativeProps.selection = this.props.selection;
}

Expand Down
Loading

0 comments on commit d2cb163

Please sign in to comment.