-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
feat: implement helper and error text support in TextInput #243
Conversation
@satya164 Can you please take a look at this? |
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 still think it's better to just separate helper text into a separate component.
<TextInput error={true} text={this.state.text} onTextChange={text => this.setState({ text })} />
<HelperText error={true}>
Please enter at least 3 characters
</HelperText>
This looks a little bit verbose, but we can add a Form
component later which handles validation for various components and reduces boilerplate.
For now, I didn't want to refactor this into a separate element -- we should do that once we know what it should look like in other components
Keep in mind that once this is merged to master, we can't change it without making it a breaking change, and I'd like to avoid that at such a short interval after the release. If you want to check how other libs do it, here is an example: https://material-ui-next.com/api/form-helper-text/
src/components/TextInput.js
Outdated
/** | ||
* Whether to style the TextInput with error style. | ||
*/ | ||
hasError: boolean, |
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 instead of this, a validate
prop might be better,
validate={text => text.length < 3 ? new Error('Please enter at least 3 characters') : null}
There are 2 advantages: first, it can be used with both controlled and uncontrolled inputs, currently, you need to maintain a state in your component to do validation. second, it reduces duplication since the logic of both checking whether there is an error and the error message are in the same place, and makes impossible states impossible, e.g. the user cannot pass hasError={true}
without an error text.
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 this should wait for the FormInput
helper.
src/components/TextInput.js
Outdated
: 0; | ||
|
||
/* Move label to top if value is set */ | ||
const labelTranslateY = value | ||
? -22 |
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.
Let's extract this number to a constant to the top of the file
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.
Done.
src/components/TextInput.js
Outdated
? -22 | ||
: this.state.focused.interpolate({ | ||
inputRange: [0, 1], | ||
outputRange: [0, -22], | ||
}); | ||
const fontSize = value | ||
|
||
const labelFontSize = value | ||
? 12 |
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.
Extract to a constant
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.
Done.
src/components/TextInput.js
Outdated
style={[styles.bottomLine, { backgroundColor: inactiveColor }]} | ||
style={[ | ||
styles.bottomLine, | ||
{ backgroundColor: (hasError && errorColor) || inactiveColor }, |
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.
hasError ? errorColor : inactiveColor
looks better
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.
Done.
src/components/TextInput.js
Outdated
style={[ | ||
styles.bottomLine, | ||
styles.focusLine, | ||
bottomLineStyle(bottomLineColor, this.state.focused), |
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.
Let's rename it to something like getBottomLineStyle
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.
Done.
src/components/TextInput.js
Outdated
/> | ||
</View> | ||
{(helperText || errorText) && ( |
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.
This will return the helperText
/errorText
if they are empty string and {(helperText || errorText) && (...)}
will evaluate to ''
, RN will throw an error saying that it's not possible to render raw string outside text. let's change this to a ternary
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.
Done.
src/styles/DarkTheme.js
Outdated
@@ -22,6 +22,11 @@ const DarkTheme: Theme = { | |||
.alpha(0.38) | |||
.rgb() | |||
.string(), | |||
helperText: color(white) |
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.
We don't put component specific styles in theme. Let's move these to the component
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 removed helperText
from here, however I think that errorText
is generic enough and helpful enough (for custom theming) to warrant its inclusion here.
How would you like the extracted component to be used? Let's assume we have a
I'm in favor of the last option. This makes sure that users don't need to spend time on possibly error-prone code. On the other hand, it encapsulates the |
|
Hi @satya164 , PTAL. |
@satya164 Please review this PR again. |
src/types.js
Outdated
text: string, | ||
disabled: string, | ||
placeholder: string, | ||
errorText: string, |
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.
We don't usually put component specific styles in theme. Also it's not clear what's the difference between error
and errorText
here. Let's move this one to the component.
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.
✅
src/components/HelperText.js
Outdated
|
||
type Props = { | ||
/** | ||
* @optional |
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.
You don't need @optional
. React docgen will infer it from flow types.
src/components/HelperText.js
Outdated
* @optional | ||
* Text color to use. | ||
*/ | ||
color?: string, |
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.
Maybe we don't need this props since people can already override the color with the theme
prop.
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.
Which theme color should be used here? The MD specs differentiate between the placeholder and helper text colors. Should we introduce a helper text color in the theme?
src/components/HelperText.js
Outdated
|
||
state: State; | ||
|
||
componentWillReceiveProps(nextProps) { |
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.
componentWillReceiveProps
is deprecated, so should use getDerivedStateFromProps
and use react-lifecycle-compat
to support older version.
Though in this case, since it does a side-effect, we should use componentDidUpdate
instead.
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.
✅
src/components/HelperText.js
Outdated
|
||
componentWillReceiveProps(nextProps) { | ||
if (nextProps.hasError !== this.props.hasError) { | ||
(nextProps.hasError ? this._animateFocus : this._animateBlur)( |
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.
Will be clearer to do:
if (nextProps.hasError) {
this._animateFocus();
} else {
this._animateBlur();
}
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.
✅
src/components/TextInput.js
Outdated
@@ -13,6 +13,11 @@ import type { Theme } from '../types'; | |||
|
|||
const AnimatedText = Animated.createAnimatedComponent(Text); | |||
|
|||
const minimizedLabelYOffset = -22; |
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.
We usually use UPPER_SNAKE_CASE
for constants
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.
✅
src/components/HelperText.js
Outdated
|
||
getHelperTextColor(dark: boolean) { | ||
return dark | ||
? colorModule(white) |
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.
Let's do:
color(theme.colors.text)
.alpha(dark ? 0.7 : 0.54)
.rgb()
.string();
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.
✅
src/components/HelperText.js
Outdated
return ( | ||
text && ( | ||
<Animated.View style={containerStyle}> | ||
{text && <Text style={[styles.helperText, { color }]}>{text}</Text>} |
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.
Redundant check
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.
✅
src/components/TextInput.js
Outdated
/** | ||
* Whether to style the TextInput with error style. | ||
*/ | ||
hasError: boolean, |
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.
Maybe just error: boolean
since we usually skip prefixes everywhere else, like disabled
, multiline
src/components/HelperText.js
Outdated
const styles = StyleSheet.create({ | ||
helperText: { | ||
fontSize: 12, | ||
marginTop: 4, |
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.
Maybe this should be marginVertical: 4
?
I applied the requested changes, let's take a look at it together on Tuesday and merge. |
@satya164 I applied the changes that we discussed today, but I kept the |
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.
9e27da8
to
2fda6f8
Compare
Please take a look at the example app for a demo of how it looks like/works. For now, I didn't want to refactor this into a separate element -- we should do that once we know what it should look like in other components. One not implemented feature is to have an icon in the error text. The material docs use error-outline, but we might consider allowing any (or any material?) icon source.
(Resolves #175)