-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Create custom TextInput #3414
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Create custom TextInput #3414
Changes from all commits
Commits
Show all changes
57 commits
Select commit
Hold shift + click to select a range
1d1847a
create custom textinput
kakajann 39a395c
merge from main
kakajann 32ac54d
restyling
kakajann 9bb3acc
change password screen implementation and small refactors
kakajann 0001f43
login screen implementation
kakajann 2e21718
payment page implementation
kakajann e95de93
merge from main
kakajann 587328d
update all textinputs to expensitextinput
kakajann 1a9687c
resolve conflicts
kakajann c9ed8ee
make ExpensiTextInput cross-platform
kakajann edbfcea
picker styles and implementations
kakajann 3ac6d2c
picker proptypes refactoring
kakajann 57de005
expensiTextInput desktop hotfixes
kakajann f2e5667
resolve conflicts
kakajann dc7b471
fix autoFocus issue
kakajann 28fa320
Merge branch 'main' of github.com:studio-504/Expensify.cash into form…
kakajann b3303c3
picker pressable issue
kakajann 0db97b8
merge from main to resolve conflicts
kakajann 8bdc856
fix lint issue
kakajann f0a779e
resolve conflicts
kakajann 229e704
add custom translate x prop to expensiInput for label transformation
kakajann 4edf386
Trigger Build
kakajann 54e20a0
Merge branch 'main' into form-styles
kakajann d5a0b00
resolve conflicts for the 9th time
kakajann 7495a56
resolve conflicts for the 10th time
kakajann f7a4b49
resolve conflicts
kakajann dc9ab22
revert podfile.lock
kakajann 048436f
android related bugfixes
kakajann 90db061
merge from main
kakajann 9cfd7e3
add size prop to ExpensiPicker
kakajann 7271cf1
change ExpensiPicker default prop
kakajann 388d015
fix desktop related issue
kakajann 1c582ce
use addOutlineWidth instead of outline: none
kakajann b6e36ea
remove android generated file
kakajann 4662b06
merge defaultProps and propTypes files for ExpensiPicker
kakajann 27c967b
remove toggleFocus on ExpensiPicker and use inline setState on onOpen…
kakajann f3c1c79
more refactors on ExpensiPicker
kakajann 19f3257
prop type refactoring for ExpensiTextInput
kakajann 221565d
refactor ExpensiTextInputLabel
kakajann f6fc27a
refactor ExpensiTextInputWrapper
kakajann 598f0cc
change containerStyles comment
kakajann 9a74f0a
more refactors for ExpensiTextInputWrapper
kakajann bd5c05b
refactor ExpensiTextInput
kakajann 83c7d18
more refactors for ExpensiTextInput
kakajann abf866f
use themeColors instead of hex
kakajann 739ce4d
styles refactor
kakajann 2f0281a
refactor ExpensiPicker styles
kakajann b2067e4
resolve conflicts
kakajann 3c2cd72
forward ExpensiTextInput ref for external usage
kakajann bc5ce35
more style refactors
kakajann ca971f3
remove redundant prop destructing from ExpensiPicker
kakajann 7976869
change Picker with ExpensiPicker
kakajann dd461b5
ExpensiTextInput refactors
kakajann 31a9efd
fix a propType typo
kakajann adeddc7
dry inputIOS and inputAndroid
kakajann 534651e
remove propTypes from style component
kakajann 8a0df8f
resolve conflict
kakajann File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,6 @@ import React from 'react'; | |
import { | ||
ActivityIndicator, | ||
View, | ||
TextInput, | ||
} from 'react-native'; | ||
import PropTypes from 'prop-types'; | ||
import lodashGet from 'lodash/get'; | ||
|
@@ -20,8 +19,9 @@ import canFocusInputOnScreenFocus from '../libs/canFocusInputOnScreenFocus'; | |
import compose from '../libs/compose'; | ||
import withLocalize, {withLocalizePropTypes} from './withLocalize'; | ||
import Button from './Button'; | ||
import Picker from './Picker'; | ||
import ExpensiPicker from './ExpensiPicker'; | ||
import Text from './Text'; | ||
import ExpensiTextInput from './ExpensiTextInput'; | ||
|
||
const propTypes = { | ||
...withLocalizePropTypes, | ||
|
@@ -161,7 +161,7 @@ class AddPlaidBankAccount extends React.Component { | |
https://d2k5nsl2zxldvw.cloudfront.net/images/plaid/[email protected] */} | ||
<Text style={[styles.mb5, styles.h1]}>{this.state.institution.name}</Text> | ||
<View style={[styles.mb5]}> | ||
<Picker | ||
<ExpensiPicker | ||
onChange={(index) => { | ||
this.setState({selectedIndex: Number(index)}); | ||
}} | ||
|
@@ -175,12 +175,9 @@ class AddPlaidBankAccount extends React.Component { | |
</View> | ||
{!_.isUndefined(this.state.selectedIndex) && ( | ||
<View style={[styles.mb5]}> | ||
<Text style={[styles.formLabel]}> | ||
{this.props.translate('addPersonalBankAccountPage.enterPassword')} | ||
</Text> | ||
<TextInput | ||
<ExpensiTextInput | ||
label={this.props.translate('addPersonalBankAccountPage.enterPassword')} | ||
secureTextEntry | ||
style={[styles.textInput, styles.mb2]} | ||
value={this.state.password} | ||
autoCompleteType="password" | ||
textContentType="password" | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import React, {PureComponent} from 'react'; | ||
import {Text, View} from 'react-native'; | ||
import PropTypes from 'prop-types'; | ||
import Picker from './Picker'; | ||
import styles from '../styles/styles'; | ||
|
||
const propTypes = { | ||
/** Picker label */ | ||
label: PropTypes.string, | ||
|
||
/** Should the picker appear disabled? */ | ||
isDisabled: PropTypes.bool, | ||
}; | ||
|
||
const defaultProps = { | ||
label: '', | ||
isDisabled: false, | ||
}; | ||
|
||
class ExpensiPicker extends PureComponent { | ||
constructor() { | ||
super(); | ||
this.state = { | ||
isOpen: false, | ||
}; | ||
} | ||
|
||
render() { | ||
const { | ||
label, isDisabled, ...pickerProps | ||
} = this.props; | ||
return ( | ||
<View | ||
style={[ | ||
styles.expensiPickerContainer, | ||
this.state.isOpen && styles.borderColorFocus, | ||
isDisabled && styles.inputDisabled, | ||
]} | ||
> | ||
{label && ( | ||
<Text style={[styles.expensiPickerLabel, styles.textLabelSupporting]}>{label}</Text> | ||
)} | ||
<Picker | ||
onOpen={() => this.setState({isOpen: true})} | ||
onClose={() => this.setState({isOpen: false})} | ||
disabled={isDisabled} | ||
// eslint-disable-next-line react/jsx-props-no-spreading | ||
{...pickerProps} | ||
/> | ||
</View> | ||
); | ||
} | ||
} | ||
|
||
ExpensiPicker.propTypes = propTypes; | ||
ExpensiPicker.defaultProps = defaultProps; | ||
|
||
export default ExpensiPicker; |
139 changes: 139 additions & 0 deletions
139
src/components/ExpensiTextInput/BaseExpensiTextInput.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
import React, {Component} from 'react'; | ||
import { | ||
Animated, TextInput, View, TouchableWithoutFeedback, | ||
} from 'react-native'; | ||
import ExpensiTextInputLabel from './ExpensiTextInputLabel'; | ||
import {propTypes, defaultProps} from './propTypes'; | ||
import themeColors from '../../styles/themes/default'; | ||
import styles from '../../styles/styles'; | ||
|
||
const ACTIVE_LABEL_TRANSLATE_Y = -10; | ||
const ACTIVE_LABEL_TRANSLATE_X = (translateX = -22) => translateX; | ||
const ACTIVE_LABEL_SCALE = 0.8668; | ||
|
||
const INACTIVE_LABEL_TRANSLATE_Y = 0; | ||
const INACTIVE_LABEL_TRANSLATE_X = 0; | ||
const INACTIVE_LABEL_SCALE = 1; | ||
|
||
class BaseExpensiTextInput extends Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
const hasValue = props.value.length > 0; | ||
|
||
this.state = { | ||
isFocused: false, | ||
labelTranslateY: new Animated.Value(hasValue ? ACTIVE_LABEL_TRANSLATE_Y : INACTIVE_LABEL_TRANSLATE_Y), | ||
labelTranslateX: new Animated.Value(hasValue | ||
? ACTIVE_LABEL_TRANSLATE_X(props.translateX) : INACTIVE_LABEL_TRANSLATE_X), | ||
labelScale: new Animated.Value(hasValue ? ACTIVE_LABEL_SCALE : INACTIVE_LABEL_SCALE), | ||
}; | ||
|
||
this.input = null; | ||
this.onFocus = this.onFocus.bind(this); | ||
this.onBlur = this.onBlur.bind(this); | ||
} | ||
|
||
onFocus() { | ||
if (this.props.onFocus) { this.props.onFocus(); } | ||
this.setState({isFocused: true}); | ||
if (this.props.value.length === 0) { | ||
this.animateLabel( | ||
ACTIVE_LABEL_TRANSLATE_Y, | ||
ACTIVE_LABEL_TRANSLATE_X(this.props.translateX), | ||
ACTIVE_LABEL_SCALE, | ||
); | ||
} | ||
} | ||
|
||
onBlur() { | ||
if (this.props.onBlur) { this.props.onBlur(); } | ||
this.setState({isFocused: false}); | ||
if (this.props.value.length === 0) { | ||
this.animateLabel(INACTIVE_LABEL_TRANSLATE_Y, INACTIVE_LABEL_TRANSLATE_X, INACTIVE_LABEL_SCALE); | ||
} | ||
} | ||
|
||
animateLabel(translateY, translateX, scale) { | ||
Animated.parallel([ | ||
Animated.spring(this.state.labelTranslateY, { | ||
toValue: translateY, | ||
duration: 80, | ||
useNativeDriver: true, | ||
}), | ||
Animated.spring(this.state.labelTranslateX, { | ||
toValue: translateX, | ||
duration: 80, | ||
useNativeDriver: true, | ||
}), | ||
Animated.spring(this.state.labelScale, { | ||
toValue: scale, | ||
duration: 80, | ||
useNativeDriver: true, | ||
}), | ||
]).start(); | ||
} | ||
|
||
render() { | ||
const { | ||
label, | ||
value, | ||
placeholder, | ||
hasError, | ||
containerStyles, | ||
inputStyle, | ||
ignoreLabelTranslateX, | ||
innerRef, | ||
...inputProps | ||
} = this.props; | ||
|
||
const hasLabel = Boolean(label.length); | ||
return ( | ||
<View style={[styles.componentHeightLarge, ...containerStyles]}> | ||
<TouchableWithoutFeedback onPress={() => this.input.focus()}> | ||
<View | ||
style={[ | ||
styles.expensiTextInputContainer, | ||
!hasLabel && styles.pv0, | ||
this.state.isFocused && styles.borderColorFocus, | ||
hasError && styles.borderColorDanger, | ||
]} | ||
> | ||
{hasLabel ? ( | ||
<ExpensiTextInputLabel | ||
label={label} | ||
labelTranslateX={ | ||
ignoreLabelTranslateX | ||
? new Animated.Value(0) | ||
: this.state.labelTranslateX | ||
} | ||
labelTranslateY={this.state.labelTranslateY} | ||
labelScale={this.state.labelScale} | ||
/> | ||
) : null} | ||
<TextInput | ||
ref={(ref) => { | ||
if (typeof innerRef === 'function') { innerRef(ref); } | ||
this.input = ref; | ||
}} | ||
// eslint-disable-next-line | ||
{...inputProps} | ||
value={value} | ||
placeholder={(this.state.isFocused || !label) ? placeholder : null} | ||
placeholderTextColor={themeColors.placeholderText} | ||
underlineColorAndroid="transparent" | ||
style={inputStyle} | ||
onFocus={this.onFocus} | ||
onBlur={this.onBlur} | ||
/> | ||
</View> | ||
</TouchableWithoutFeedback> | ||
</View> | ||
); | ||
} | ||
} | ||
|
||
BaseExpensiTextInput.propTypes = propTypes; | ||
BaseExpensiTextInput.defaultProps = defaultProps; | ||
|
||
export default BaseExpensiTextInput; |
30 changes: 30 additions & 0 deletions
30
src/components/ExpensiTextInput/ExpensiTextInputLabel/index.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import React, {memo} from 'react'; | ||
import {Animated} from 'react-native'; | ||
import styles from '../../../styles/styles'; | ||
import propTypes from './propTypes'; | ||
|
||
const ExpensiTextInputLabel = ({ | ||
label, | ||
labelTranslateY, | ||
labelTranslateX, | ||
labelScale, | ||
}) => ( | ||
<Animated.Text | ||
style={[ | ||
styles.expensiTextInputLabel, | ||
styles.expensiTextInputLabelDesktop, | ||
styles.expensiTextInputLabelTransformation( | ||
labelTranslateY, | ||
labelTranslateX, | ||
labelScale, | ||
), | ||
]} | ||
> | ||
{label} | ||
</Animated.Text> | ||
); | ||
|
||
ExpensiTextInputLabel.propTypes = propTypes; | ||
ExpensiTextInputLabel.displayName = 'ExpensiTextInputLabel'; | ||
|
||
export default memo(ExpensiTextInputLabel); |
29 changes: 29 additions & 0 deletions
29
src/components/ExpensiTextInput/ExpensiTextInputLabel/index.native.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import React, {memo} from 'react'; | ||
import {Animated} from 'react-native'; | ||
import styles from '../../../styles/styles'; | ||
import propTypes from './propTypes'; | ||
|
||
const ExpensiTextInputLabel = ({ | ||
label, | ||
labelTranslateX, | ||
labelTranslateY, | ||
labelScale, | ||
}) => ( | ||
<Animated.Text | ||
style={[ | ||
styles.expensiTextInputLabel, | ||
styles.expensiTextInputLabelTransformation( | ||
labelTranslateY, | ||
labelTranslateX, | ||
labelScale, | ||
), | ||
]} | ||
> | ||
{label} | ||
</Animated.Text> | ||
); | ||
|
||
ExpensiTextInputLabel.propTypes = propTypes; | ||
ExpensiTextInputLabel.displayName = 'ExpensiTextInputLabel'; | ||
|
||
export default memo(ExpensiTextInputLabel); |
18 changes: 18 additions & 0 deletions
18
src/components/ExpensiTextInput/ExpensiTextInputLabel/propTypes.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import PropTypes from 'prop-types'; | ||
import {Animated} from 'react-native'; | ||
|
||
const propTypes = { | ||
/** Label */ | ||
label: PropTypes.string, | ||
|
||
/** Label vertical translate */ | ||
labelTranslateY: PropTypes.instanceOf(Animated.Value).isRequired, | ||
|
||
/** Label horizontal translate */ | ||
labelTranslateX: PropTypes.instanceOf(Animated.Value).isRequired, | ||
|
||
/** Label scale */ | ||
labelScale: PropTypes.instanceOf(Animated.Value).isRequired, | ||
}; | ||
|
||
export default propTypes; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like
pickerProps
is onlysize
for now, so why don't you just passsize={size}
(and only destructuresize
out ofthis.props
above) so you can avoid the eslint override?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there's more props than only
size
onChange
,items
,icon
also passed withpickerProps
I should remove
placeholder
,value
fromthis.props
destruction to make the code clearer