mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-04-29 04:44:52 +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 secureTextEntry />
|
||||||
<TextInput defaultValue='read only' editable={false} />
|
<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='numeric' />
|
||||||
<TextInput keyboardType='phone-pad' />
|
<TextInput keyboardType='phone-pad' />
|
||||||
<TextInput defaultValue='https://delete-me' keyboardType='url' placeholder='https://www.some-website.com' selectTextOnFocus />
|
<TextInput defaultValue='https://delete-me' keyboardType='url' placeholder='https://www.some-website.com' selectTextOnFocus />
|
||||||
|
|||||||
@@ -180,17 +180,17 @@ suite('components/TextInput', () => {
|
|||||||
test('prop "placeholder"', () => {
|
test('prop "placeholder"', () => {
|
||||||
const placeholder = 'placeholder'
|
const placeholder = 'placeholder'
|
||||||
const result = findShallowPlaceholder(utils.shallowRender(<TextInput 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"', () => {
|
test('prop "placeholderTextColor"', () => {
|
||||||
const placeholder = 'placeholder'
|
const placeholder = 'placeholder'
|
||||||
|
|
||||||
let result = findShallowPlaceholder(utils.shallowRender(<TextInput 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' />))
|
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"', () => {
|
test('prop "secureTextEntry"', () => {
|
||||||
|
|||||||
@@ -66,50 +66,6 @@ class TextInput extends Component {
|
|||||||
this.refs.input.setNativeProps(props)
|
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() {
|
render() {
|
||||||
const {
|
const {
|
||||||
/* eslint-disable react/prop-types */
|
/* eslint-disable react/prop-types */
|
||||||
@@ -163,10 +119,10 @@ class TextInput extends Component {
|
|||||||
autoFocus,
|
autoFocus,
|
||||||
defaultValue,
|
defaultValue,
|
||||||
maxLength,
|
maxLength,
|
||||||
onBlur: this._onBlur,
|
onBlur: this._handleBlur,
|
||||||
onChange: this._onChange,
|
onChange: this._handleChange,
|
||||||
onFocus: this._onFocus,
|
onFocus: this._handleFocus,
|
||||||
onSelect: onSelectionChange && this._onSelectionChange,
|
onSelect: onSelectionChange && this._handleSelectionChange,
|
||||||
readOnly: !editable,
|
readOnly: !editable,
|
||||||
style: { ...styles.input, outline: style.outline },
|
style: { ...styles.input, outline: style.outline },
|
||||||
value
|
value
|
||||||
@@ -190,25 +146,76 @@ class TextInput extends Component {
|
|||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
accessibilityLabel={accessibilityLabel}
|
accessibilityLabel={accessibilityLabel}
|
||||||
style={[
|
onClick={this._handleClick}
|
||||||
styles.initial,
|
style={[ styles.initial, style ]}
|
||||||
style
|
|
||||||
]}
|
|
||||||
testID={testID}
|
testID={testID}
|
||||||
>
|
>
|
||||||
<View style={styles.wrapper}>
|
<View style={styles.wrapper}>
|
||||||
{createNativeComponent({ ...props, ref: 'input' })}
|
{createNativeComponent({ ...props, ref: 'input' })}
|
||||||
{placeholder && this.state.showPlaceholder && <Text
|
{placeholder && this.state.showPlaceholder && (
|
||||||
pointerEvents='none'
|
<View pointerEvents='none' style={styles.placeholder}>
|
||||||
style={[
|
<Text
|
||||||
styles.placeholder,
|
children={placeholder}
|
||||||
placeholderTextColor && { color: placeholderTextColor }
|
style={[
|
||||||
]}
|
styles.placeholderText,
|
||||||
>{placeholder}</Text>}
|
placeholderTextColor && { color: placeholderTextColor }
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
</View>
|
</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({
|
const styles = StyleSheet.create({
|
||||||
@@ -232,12 +239,15 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
placeholder: {
|
placeholder: {
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
color: 'darkgray',
|
justifyContent: 'center',
|
||||||
left: 0,
|
left: 0,
|
||||||
overflow: 'hidden',
|
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
right: 0,
|
right: 0,
|
||||||
top: 0,
|
top: 0
|
||||||
|
},
|
||||||
|
placeholderText: {
|
||||||
|
color: 'darkgray',
|
||||||
|
overflow: 'hidden',
|
||||||
whiteSpace: 'pre'
|
whiteSpace: 'pre'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user