mfrag38-react-native-textinput-with-icons-full
Version:
small react native package help you to make a material text input and allow you to add icons to the left and right side and icons have onPress feature
611 lines (586 loc) • 13.7 kB
JavaScript
import React, { Component } from 'react';
import { View, TextInput, Platform, Dimensions } from 'react-native';
import PropTypes from 'prop-types';
import Label from './Label';
import Placeholder from './Placeholder';
import Underline from './Underline';
import ErrorHelper from './ErrorHelper';
import {
AwesomeIcon,
IonIcon,
EvilIcon,
MaterialDesignIcon,
OctIcon,
} from './icons';
import ClickableView from 'mfrag38-react-native-clickable-view';
export default class extends Component {
static propTypes = {
...TextInput.PropTypes,
...ErrorHelper.PropTypes,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
onChangeText: PropTypes.func,
onContentSizeChange: PropTypes.func,
minHeight: PropTypes.number,
height: PropTypes.number,
maxHeight: PropTypes.number,
marginTop: PropTypes.number,
marginRight: PropTypes.number,
marginBottom: PropTypes.number,
marginLeft: PropTypes.number,
paddingTop: PropTypes.number,
paddingRight: PropTypes.number,
paddingBottom: PropTypes.number,
paddingLeft: PropTypes.number,
color: PropTypes.string,
activeColor: PropTypes.string,
fontFamily: PropTypes.string,
fontSize: PropTypes.number,
fontWeight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
leftIcon: PropTypes.string,
leftIconColor: PropTypes.string,
leftIconSize: PropTypes.number,
leftIconType: PropTypes.string,
onPressLeftIcon: PropTypes.func,
rightIcon: PropTypes.string,
rightIconColor: PropTypes.string,
rightIconSize: PropTypes.number,
rightIconType: PropTypes.string,
onPressRightIcon: PropTypes.func,
rippleColor: PropTypes.string,
};
static defaultProps = {
...ErrorHelper.defaultProps,
onFocus: () => {},
onBlur: () => {},
onChangeText: () => {},
onContentSizeChange: () => {},
value: null,
marginBottom: 8,
paddingTop: 20,
paddingRight: 0,
paddingBottom: 8,
paddingLeft: 0,
color: 'black',
fontSize: 15,
fontWeight: 'normal',
rippleColor: 'rgba(220,220,220,10)',
rightIconType: 'ion',
leftIconType: 'ion',
rightIconSize: 15,
leftIconSize: 15,
rightIconColor: '#777777',
leftIconColor: '#777777',
};
constructor(props) {
super(props);
this.state = {
value: null,
focused: false,
height: props.fontSize * 1.5,
iconPaddingRight: 0,
iconPaddingLeft: 0,
};
}
componentWillMount() {
this._iconPaddingLeft();
this._iconPaddingRight();
}
componentDidMount() {
if (this.props.refrance) {
this.props.refrance(this.refs.refrance);
}
}
render() {
let { focused, height, iconPaddingLeft, iconPaddingRight } = this.state;
let value =
this.props.value != null ? this.props.value : this.state.value;
let hasValue = value && value.length > 0;
let active = focused || hasValue;
const { width } = Dimensions.get('window');
const maxWidth = width - (width * 20) / 100;
let {
minHeight,
maxHeight,
marginTop,
marginRight,
marginBottom,
marginLeft,
paddingTop,
paddingRight,
paddingBottom,
paddingLeft,
color,
activeColor,
fontFamily,
fontSize,
fontWeight,
label,
labelDuration,
labelColor,
labelActiveTop,
labelActiveColor,
labelActiveScale,
placeholder,
placeholderColor,
underlineDuration,
underlineHeight,
underlineColor,
underlineActiveColor,
underlineActiveHeight,
error,
errorColor,
errorPaddingTop,
errorFontSize,
containerWidth,
containerMaxWidth,
containerMinWidth,
containerMaxHeight,
containerMarginBottom,
RTL,
leftIcon,
leftIconSize,
leftIconColor,
leftIconType,
onPressLeftIcon,
rightIcon,
rightIconSize,
rightIconColor,
rightIconType,
onPressRightIcon,
rippleColor,
...props
} = this.props;
let labelProps = {
paddingTop,
paddingRight,
paddingBottom,
paddingLeft,
activeColor,
fontFamily,
fontSize,
fontWeight,
label,
labelDuration,
labelColor,
labelActiveTop,
labelActiveColor,
labelActiveScale,
focused,
hasValue,
error,
errorColor,
RTL,
};
let placeholderProps = {
paddingTop,
paddingRight,
paddingBottom,
paddingLeft,
fontFamily,
fontSize,
fontWeight,
placeholder,
placeholderColor,
focused,
hasValue,
};
let underlineProps = {
activeColor,
underlineDuration,
underlineHeight,
underlineColor,
underlineActiveColor,
underlineActiveHeight,
focused,
error,
errorColor,
};
let containerStyle = {
marginTop,
marginRight,
marginBottom,
marginLeft,
};
if (props.multiline && props.height) {
// Disable autogrow if height prop
height = props.height;
}
let inputStyle = {
minHeight,
maxHeight,
paddingTop,
paddingRight,
paddingBottom,
paddingLeft,
color,
fontFamily,
fontSize,
fontWeight,
...Platform.select({
ios: {
height:
paddingTop +
paddingBottom +
(props.multiline ? height : fontSize * 1.5),
},
android: {
height: props.multiline
? height
: fontSize * 1.5 + paddingTop + paddingBottom,
textAlignVertical: 'top',
},
}),
};
let errorProps = {
error,
errorColor,
errorPaddingTop,
errorFontSize,
};
let containerCustomStyle = {
width: containerWidth || width,
maxWidth: containerMaxWidth ? containerMaxWidth : maxWidth,
minWidth: containerMinWidth ? containerMinWidth : 150,
maxHeight: containerMaxHeight ? containerMaxHeight : 150,
marginBottom: containerMarginBottom ? containerMarginBottom : 0,
};
let iconStyle = {
position: 'absolute',
zIndex: 5,
height: '100%',
justifyContent: 'center',
alignItems: 'center',
};
return (
<View style={[containerCustomStyle]}>
{leftIcon &&
this._iconGenerator(
iconStyle,
rippleColor,
!RTL ? leftIconType : rightIconType,
!RTL ? leftIcon : rightIcon,
focused && !RTL
? labelActiveColor
? labelActiveColor
: '#3f51b5'
: leftIconColor,
leftIconSize,
'left',
onPressLeftIcon,
containerWidth ? containerWidth : width,
maxWidth,
)}
{rightIcon &&
this._iconGenerator(
iconStyle,
rippleColor,
RTL ? leftIconType : rightIconType,
RTL ? leftIcon : rightIcon,
focused && RTL
? labelActiveColor
? labelActiveColor
: '#3f51b5'
: rightIconColor,
rightIconSize,
'right',
onPressRightIcon,
containerWidth ? containerWidth : width,
maxWidth,
)}
<View style={containerStyle}>
<Label
{...labelProps}
paddingRight={iconPaddingRight}
paddingLeft={iconPaddingLeft}
/>
{placeholder ? <Placeholder {...placeholderProps} /> : null}
<TextInput
{...props}
style={inputStyle}
ref={'refrance'}
paddingRight={iconPaddingRight}
paddingLeft={iconPaddingLeft}
underlineColorAndroid='transparent'
onFocus={this._handleFocus}
onBlur={this._handleBlur}
onChangeText={this._handleChangeText}
onContentSizeChange={this._handleContentSizeChange}
value={value}
/>
<Underline {...underlineProps} />
{error ? <ErrorHelper {...errorProps} /> : null}
</View>
</View>
);
}
_handleFocus = (...args) => {
let { onFocus } = this.props;
this.setState({ focused: true });
onFocus(...args);
};
_handleBlur = (...args) => {
let { onBlur } = this.props;
this.setState({ focused: false });
onBlur(...args);
};
_handleChangeText = (...args) => {
let { onChangeText, value } = this.props;
// Make support of uncontrolled component
if (value == null) {
this.setState({ value: args[0] });
}
onChangeText(...args);
};
_handleContentSizeChange = event => {
let { onContentSizeChange, fontSize } = this.props;
let { height } = event.nativeEvent.contentSize;
this.setState({
height: Math.max(fontSize * 1.5, Math.ceil(height)),
});
onContentSizeChange(event);
};
_iconPaddingLeft() {
const {
leftIcon,
leftIconSize,
paddingStart,
paddingLeft,
} = this.props;
let statePaddingLeft = 0;
if (leftIcon && leftIconSize) {
statePaddingLeft = leftIconSize + 10;
this.setState({
iconPaddingLeft: statePaddingLeft,
});
} else if (paddingStart || paddingLeft) {
statePaddingLeft = paddingStart || paddingLeft;
this.setState({
iconPaddingLeft: statePaddingLeft,
});
}
}
_iconPaddingRight() {
const {
rightIcon,
rightIconSize,
paddingEnd,
paddingRight,
} = this.props;
let statePaddingRight = 0;
if (rightIcon && rightIconSize) {
statePaddingRight = rightIconSize + 10;
this.setState({
iconPaddingRight: statePaddingRight,
});
} else if (paddingEnd || paddingRight) {
statePaddingRight = paddingEnd || paddingRight;
this.setState({
iconPaddingRight: statePaddingRight,
});
}
}
_iconGenerator(
iconStyle,
rippleColor,
iconType,
iconName,
iconColor,
iconSize,
iconPosition,
onPressIcon,
parentWidth,
maxWidth,
) {
let Type = iconType ? iconType.toLowerCase() : null;
// get input width to set icon position
let inputWidth =
parentWidth < 150
? 150
: parentWidth > maxWidth
? maxWidth
: parentWidth;
switch (Type) {
case 'ion':
return (
<ClickableView
rippleColor={rippleColor}
style={[
iconStyle,
{
width: iconSize,
left:
iconPosition === 'left'
? 0
: inputWidth - iconSize - 5,
bottom: this.props.error ? 12 : 0,
},
]}
>
<IonIcon
icon={iconName}
color={
this.props.error && iconPosition === 'left'
? this.props.errorColor
? this.props.errorColor
: 'red'
: iconColor
}
size={iconSize}
onPress={onPressIcon}
/>
</ClickableView>
);
case 'oct':
return (
<ClickableView
rippleColor={rippleColor}
style={[
iconStyle,
{
width: iconSize,
left:
iconPosition === 'left'
? 0
: inputWidth - iconSize - 10,
bottom: this.props.error ? 12 : 0,
},
]}
>
<OctIcon
icon={iconName}
color={
this.props.error && iconPosition === 'left'
? this.props.errorColor
? this.props.errorColor
: 'red'
: iconColor
}
size={iconSize}
onPress={onPressIcon}
/>
</ClickableView>
);
case 'evil':
return (
<ClickableView
rippleColor={rippleColor}
style={[
iconStyle,
{
width: iconSize,
left:
iconPosition === 'left'
? 0
: inputWidth - iconSize - 10,
bottom: this.props.error ? 12 : 0,
},
]}
>
<EvilIcon
icon={iconName}
color={
this.props.error && iconPosition === 'left'
? this.props.errorColor
? this.props.errorColor
: 'red'
: iconColor
}
size={iconSize}
onPress={onPressIcon}
/>
</ClickableView>
);
case 'awesome':
return (
<ClickableView
rippleColor={rippleColor}
style={[
iconStyle,
{
width: iconSize,
left:
iconPosition === 'left'
? 0
: inputWidth - iconSize - 10,
bottom: this.props.error ? 12 : 0,
},
]}
>
<AwesomeIcon
icon={iconName}
color={
this.props.error && iconPosition === 'left'
? this.props.errorColor
? this.props.errorColor
: 'red'
: iconColor
}
size={iconSize}
onPress={onPressIcon}
/>
</ClickableView>
);
case 'material':
return (
<ClickableView
rippleColor={rippleColor}
style={[
iconStyle,
{
width: iconSize,
left:
iconPosition === 'left'
? 0
: inputWidth - iconSize - 10,
bottom: this.props.error ? 12 : 0,
},
]}
>
<MaterialDesignIcon
icon={iconName}
color={
this.props.error && iconPosition === 'left'
? this.props.errorColor
? this.props.errorColor
: 'red'
: iconColor
}
size={iconSize}
onPress={onPressIcon}
/>
</ClickableView>
);
default:
return (
<ClickableView
rippleColor={rippleColor}
style={[
iconStyle,
{
width: iconSize,
left:
iconPosition === 'left'
? 0
: inputWidth - iconSize - 10,
bottom: this.props.error ? 12 : 0,
},
]}
>
<IonIcon
icon={iconName}
color={
this.props.error && iconPosition === 'left'
? this.props.errorColor
? this.props.errorColor
: 'red'
: iconColor
}
size={iconSize}
onPress={onPressIcon}
/>
</ClickableView>
);
}
}
}