-
Notifications
You must be signed in to change notification settings - Fork 455
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add EmptyStateView, NumberInput and SearchField from @shoutem/ui-addons
- Loading branch information
Showing
5 changed files
with
315 additions
and
6 deletions.
There are no files selected for viewing
This file contains 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,74 @@ | ||
import React, { PureComponent } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
import { connectStyle } from '@shoutem/theme'; | ||
|
||
import Icon from './Icon'; | ||
import View from './View'; | ||
import Text from './Text'; | ||
import Button from './Button'; | ||
import Subtitle from './Subtitle'; | ||
|
||
class EmptyStateView extends PureComponent { | ||
static defaultProps = { | ||
retryButtonTitle: 'TRY AGAIN', | ||
icon: 'error', | ||
} | ||
|
||
constructor(props) { | ||
super(props); | ||
|
||
this.onRetry = this.onRetry.bind(this); | ||
this.renderRetryButton = this.renderRetryButton.bind(this); | ||
} | ||
|
||
onRetry() { | ||
this.props.onRetry(); | ||
} | ||
|
||
renderRetryButton() { | ||
const { retryButtonTitle } = this.props; | ||
|
||
// Show retry button at the bottom only if | ||
// there is a onRetry action passed. | ||
return ( | ||
<View styleName="horizontal anchor-bottom"> | ||
<Button styleName="full-width" onPress={this.onRetry}> | ||
<Text>{retryButtonTitle}</Text> | ||
</Button> | ||
</View> | ||
); | ||
} | ||
|
||
render() { | ||
const { icon, message, onRetry } = this.props; | ||
|
||
return ( | ||
<View | ||
{...this.props} | ||
styleName="vertical flexible h-center v-center" | ||
> | ||
<View styleName="icon-placeholder"> | ||
<Icon name={icon} /> | ||
</View> | ||
|
||
<Subtitle styleName="h-center">{message}</Subtitle> | ||
|
||
{onRetry && this.renderRetryButton()} | ||
</View> | ||
); | ||
} | ||
} | ||
|
||
EmptyStateView.propTypes = { | ||
...EmptyStateView.propTypes, | ||
onRetry: PropTypes.func, | ||
message: PropTypes.string, | ||
icon: PropTypes.string, | ||
}; | ||
|
||
const StyledView = connectStyle('shoutem.ui.EmptyStateView')(EmptyStateView); | ||
|
||
export { | ||
StyledView as EmptyStateView, | ||
}; |
This file contains 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,141 @@ | ||
import React, { PureComponent } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import _ from 'lodash'; | ||
|
||
import { connectStyle } from '@shoutem/theme'; | ||
import { connectAnimation } from '@shoutem/animation'; | ||
|
||
import Icon from './Icon'; | ||
import View from './View'; | ||
import Button from './Button'; | ||
import TextInput from './TextInput'; | ||
|
||
const { func, number, object, oneOfType, shape, string } = PropTypes; | ||
|
||
/** | ||
* A component for entering a numerical value with two helper buttons for increasing | ||
* and decreasing the value. | ||
* | ||
* The current implementation allows only positive integers. It removes any character | ||
* that is not a digit, if the user enters it directly or by pasting. | ||
* | ||
* The component allows empty values. The consumer needs to handle it as he sees fit. | ||
* | ||
* TODO: Future implementations should define how to handle validation in combination with | ||
* focus and blur events. | ||
*/ | ||
class NumberInput extends PureComponent { | ||
static propTypes = { | ||
...TextInput.propTypes, | ||
// Maximum allowed value | ||
max: number, | ||
// Minimum allowed value | ||
min: number, | ||
// Called when the user changes the value by inputting it directly or with buttons | ||
onChange: func.isRequired, | ||
// Step used to increase or decrease value with corresponding buttons | ||
step: number, | ||
// Styles for component parts | ||
style: shape({ | ||
button: object, | ||
container: object, | ||
icon: object, | ||
input: object, | ||
inputContainer: object, | ||
}), | ||
// Value of the input - can be empty | ||
value: oneOfType([ | ||
number, | ||
string, | ||
]), | ||
}; | ||
|
||
constructor(props) { | ||
super(props); | ||
|
||
this.decreaseValue = this.decreaseValue.bind(this); | ||
this.increaseValue = this.increaseValue.bind(this); | ||
this.onChangeText = this.onChangeText.bind(this); | ||
} | ||
|
||
onChangeText(text) { | ||
const transformedText = text.replace(/[^0-9]/g, ''); | ||
|
||
this.updateValue(parseInt(transformedText, 10)); | ||
} | ||
|
||
decreaseValue() { | ||
const { step = 1, value = 0 } = this.props; | ||
|
||
this.updateValue(value - step); | ||
} | ||
|
||
increaseValue() { | ||
const { step = 1, value = 0 } = this.props; | ||
|
||
this.updateValue(value + step); | ||
} | ||
|
||
updateValue(value) { | ||
const { max, min, onChange } = this.props; | ||
|
||
if (!_.isFinite(value)) { | ||
return onChange(''); | ||
} | ||
|
||
let newValue = _.isFinite(max) && value > max ? max : value; | ||
newValue = _.isFinite(min) && newValue < min ? min : newValue; | ||
|
||
return onChange(newValue); | ||
} | ||
|
||
render() { | ||
const { style, value } = this.props; | ||
|
||
return ( | ||
<View | ||
style={style.container} | ||
styleName="horizontal" | ||
> | ||
<Button | ||
style={style.button} | ||
styleName="secondary" | ||
onPress={this.decreaseValue} | ||
> | ||
<Icon | ||
name="minus-button" | ||
style={style.icon} | ||
/> | ||
</Button> | ||
<View | ||
style={style.inputContainer} | ||
styleName="horizontal" | ||
> | ||
<TextInput | ||
keyboardType="numeric" | ||
onChangeText={this.onChangeText} | ||
style={style.input} | ||
value={`${value}`} | ||
/> | ||
</View> | ||
<Button | ||
style={style.button} | ||
styleName="secondary" | ||
onPress={this.increaseValue} | ||
> | ||
<Icon | ||
name="plus-button" | ||
style={style.icon} | ||
/> | ||
</Button> | ||
</View> | ||
); | ||
} | ||
} | ||
|
||
const AnimatedNumberInput = connectAnimation(NumberInput); | ||
const StyledNumberInput = connectStyle('shoutem.ui.NumberInput')(AnimatedNumberInput); | ||
|
||
export { | ||
StyledNumberInput as NumberInput, | ||
}; |
This file contains 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,90 @@ | ||
import React, { PureComponent } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
import { connectStyle } from '@shoutem/theme'; | ||
import { connectAnimation } from '@shoutem/animation'; | ||
|
||
import Icon from './Icon'; | ||
import View from './View'; | ||
import Button from './Button'; | ||
import TextInput from './TextInput'; | ||
|
||
const { func, object, shape, string } = PropTypes; | ||
|
||
const ClearButton = ({ style, onPress }) => ( | ||
<Button | ||
styleName="clear tight" | ||
onPress={onPress} | ||
> | ||
<Icon | ||
name="clear-text" | ||
style={style.clearIcon} | ||
/> | ||
</Button> | ||
); | ||
|
||
ClearButton.propTypes = { | ||
style: object, | ||
onPress: func, | ||
}; | ||
|
||
/** | ||
* A component that allows the user to enter a search query. | ||
* It has a search icon, placeholder and a button that clears the current query. | ||
* | ||
*/ | ||
class SearchField extends PureComponent { | ||
static propTypes = { | ||
// A placeholder for input when no value is entered | ||
placeholder: string, | ||
// Called with the new value on text change | ||
onChangeText: func, | ||
// Styles for container and search icon | ||
style: shape({ | ||
clearIcon: object, | ||
container: object, | ||
input: object, | ||
searchIcon: object, | ||
}), | ||
// Value to render as text in search input | ||
value: string, | ||
}; | ||
|
||
render() { | ||
const { onChangeText, placeholder, style, value, ...rest } = this.props; | ||
|
||
return ( | ||
<View | ||
style={style.container} | ||
styleName="horizontal sm-gutter-horizontal v-center" | ||
> | ||
<Icon | ||
name="search" | ||
style={style.searchIcon} | ||
/> | ||
<TextInput | ||
{...rest} | ||
autoCapitalize="none" | ||
autoCorrect={false} | ||
onChangeText={onChangeText} | ||
placeholder={placeholder} | ||
style={style.input} | ||
value={value} | ||
/> | ||
{value && ( | ||
<ClearButton | ||
onPress={() => onChangeText('')} | ||
style={style} | ||
/> | ||
)} | ||
</View> | ||
); | ||
} | ||
} | ||
|
||
const AnimatedSearchField = connectAnimation(SearchField); | ||
const StyledSearchField = connectStyle('shoutem.ui.SearchField')(AnimatedSearchField); | ||
|
||
export { | ||
StyledSearchField as SearchField, | ||
}; |
This file contains 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 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