mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-01-12 22:51:09 +08:00
[fix] TextInput placeholder layout and focus
Fix the layout of placeholder text and shift focus to the DOM input when `TextInput` is clicked or pressed. Thanks to @tuckerconnelly and @Dremora. Fix #138 Fix #119 Close #137
This commit is contained in:
@@ -90,7 +90,7 @@ export default class App extends React.Component {
|
||||
/>
|
||||
<TextInput secureTextEntry />
|
||||
<TextInput defaultValue='read only' editable={false} />
|
||||
<TextInput keyboardType='email-address' placeholder='you@domain.com' placeholderTextColor='red' />
|
||||
<TextInput style={{ flex:1, height: 60, padding: 20 }} keyboardType='email-address' placeholder='you@domain.com' placeholderTextColor='red' />
|
||||
<TextInput keyboardType='numeric' />
|
||||
<TextInput keyboardType='phone-pad' />
|
||||
<TextInput defaultValue='https://delete-me' keyboardType='url' placeholder='https://www.some-website.com' selectTextOnFocus />
|
||||
|
||||
@@ -180,17 +180,17 @@ suite('components/TextInput', () => {
|
||||
test('prop "placeholder"', () => {
|
||||
const placeholder = 'placeholder'
|
||||
const result = findShallowPlaceholder(utils.shallowRender(<TextInput placeholder={placeholder} />))
|
||||
assert.equal(result.props.children, placeholder)
|
||||
assert.equal(result.props.children.props.children, placeholder)
|
||||
})
|
||||
|
||||
test('prop "placeholderTextColor"', () => {
|
||||
const placeholder = 'placeholder'
|
||||
|
||||
let result = findShallowPlaceholder(utils.shallowRender(<TextInput placeholder={placeholder} />))
|
||||
assert.equal(StyleSheet.flatten(result.props.style).color, 'darkgray')
|
||||
assert.equal(StyleSheet.flatten(result.props.children.props.style).color, 'darkgray')
|
||||
|
||||
result = findShallowPlaceholder(utils.shallowRender(<TextInput placeholder={placeholder} placeholderTextColor='red' />))
|
||||
assert.equal(StyleSheet.flatten(result.props.style).color, 'red')
|
||||
assert.equal(StyleSheet.flatten(result.props.children.props.style).color, 'red')
|
||||
})
|
||||
|
||||
test('prop "secureTextEntry"', () => {
|
||||
|
||||
@@ -66,50 +66,6 @@ class TextInput extends Component {
|
||||
this.refs.input.setNativeProps(props)
|
||||
}
|
||||
|
||||
_onBlur = (e) => {
|
||||
const { onBlur } = this.props
|
||||
const text = e.target.value
|
||||
this.setState({ showPlaceholder: text === '' })
|
||||
this.blur()
|
||||
if (onBlur) onBlur(e)
|
||||
}
|
||||
|
||||
_onChange = (e) => {
|
||||
const { onChange, onChangeText } = this.props
|
||||
const text = e.target.value
|
||||
this.setState({ showPlaceholder: text === '' })
|
||||
if (onChange) onChange(e)
|
||||
if (onChangeText) onChangeText(text)
|
||||
if (!this.refs.input) {
|
||||
// calling `this.props.onChange` or `this.props.onChangeText`
|
||||
// may clean up the input itself. Exits here.
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
_onFocus = (e) => {
|
||||
const { clearTextOnFocus, onFocus, selectTextOnFocus } = this.props
|
||||
const node = ReactDOM.findDOMNode(this.refs.input)
|
||||
const text = e.target.value
|
||||
this.focus()
|
||||
if (onFocus) onFocus(e)
|
||||
if (clearTextOnFocus) this.clear()
|
||||
if (selectTextOnFocus) node.select()
|
||||
this.setState({ showPlaceholder: text === '' })
|
||||
}
|
||||
|
||||
_onSelectionChange = (e) => {
|
||||
const { onSelectionChange } = this.props
|
||||
const { selectionDirection, selectionEnd, selectionStart } = e.target
|
||||
const event = {
|
||||
selectionDirection,
|
||||
selectionEnd,
|
||||
selectionStart,
|
||||
nativeEvent: e.nativeEvent
|
||||
}
|
||||
if (onSelectionChange) onSelectionChange(event)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
/* eslint-disable react/prop-types */
|
||||
@@ -163,10 +119,10 @@ class TextInput extends Component {
|
||||
autoFocus,
|
||||
defaultValue,
|
||||
maxLength,
|
||||
onBlur: this._onBlur,
|
||||
onChange: this._onChange,
|
||||
onFocus: this._onFocus,
|
||||
onSelect: onSelectionChange && this._onSelectionChange,
|
||||
onBlur: this._handleBlur,
|
||||
onChange: this._handleChange,
|
||||
onFocus: this._handleFocus,
|
||||
onSelect: onSelectionChange && this._handleSelectionChange,
|
||||
readOnly: !editable,
|
||||
style: { ...styles.input, outline: style.outline },
|
||||
value
|
||||
@@ -190,25 +146,76 @@ class TextInput extends Component {
|
||||
return (
|
||||
<View
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
style={[
|
||||
styles.initial,
|
||||
style
|
||||
]}
|
||||
onClick={this._handleClick}
|
||||
style={[ styles.initial, style ]}
|
||||
testID={testID}
|
||||
>
|
||||
<View style={styles.wrapper}>
|
||||
{createNativeComponent({ ...props, ref: 'input' })}
|
||||
{placeholder && this.state.showPlaceholder && <Text
|
||||
pointerEvents='none'
|
||||
style={[
|
||||
styles.placeholder,
|
||||
placeholderTextColor && { color: placeholderTextColor }
|
||||
]}
|
||||
>{placeholder}</Text>}
|
||||
{placeholder && this.state.showPlaceholder && (
|
||||
<View pointerEvents='none' style={styles.placeholder}>
|
||||
<Text
|
||||
children={placeholder}
|
||||
style={[
|
||||
styles.placeholderText,
|
||||
placeholderTextColor && { color: placeholderTextColor }
|
||||
]}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
_handleBlur = (e) => {
|
||||
const { onBlur } = this.props
|
||||
const text = e.target.value
|
||||
this.setState({ showPlaceholder: text === '' })
|
||||
this.blur()
|
||||
if (onBlur) onBlur(e)
|
||||
}
|
||||
|
||||
_handleChange = (e) => {
|
||||
const { onChange, onChangeText } = this.props
|
||||
const text = e.target.value
|
||||
this.setState({ showPlaceholder: text === '' })
|
||||
if (onChange) onChange(e)
|
||||
if (onChangeText) onChangeText(text)
|
||||
if (!this.refs.input) {
|
||||
// calling `this.props.onChange` or `this.props.onChangeText`
|
||||
// may clean up the input itself. Exits here.
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
_handleClick = (e) => {
|
||||
this.focus()
|
||||
}
|
||||
|
||||
_handleFocus = (e) => {
|
||||
const { clearTextOnFocus, onFocus, selectTextOnFocus } = this.props
|
||||
const node = ReactDOM.findDOMNode(this.refs.input)
|
||||
const text = e.target.value
|
||||
if (onFocus) onFocus(e)
|
||||
if (clearTextOnFocus) this.clear()
|
||||
if (selectTextOnFocus) node.select()
|
||||
this.setState({ showPlaceholder: text === '' })
|
||||
}
|
||||
|
||||
_handleSelectionChange = (e) => {
|
||||
const { onSelectionChange } = this.props
|
||||
try {
|
||||
const { selectionDirection, selectionEnd, selectionStart } = e.target
|
||||
const event = {
|
||||
selectionDirection,
|
||||
selectionEnd,
|
||||
selectionStart,
|
||||
nativeEvent: e.nativeEvent
|
||||
}
|
||||
if (onSelectionChange) onSelectionChange(event)
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
@@ -232,12 +239,15 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
placeholder: {
|
||||
bottom: 0,
|
||||
color: 'darkgray',
|
||||
justifyContent: 'center',
|
||||
left: 0,
|
||||
overflow: 'hidden',
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 0,
|
||||
top: 0
|
||||
},
|
||||
placeholderText: {
|
||||
color: 'darkgray',
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'pre'
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user