@spring-global/react-native-input-spinner
Version:
React native numeric spinner fork from https://www.npmjs.com/package/react-native-input-spinner
1,560 lines (1,437 loc) • 42.7 kB
JavaScript
import React, { Component } from "react";
import {
Platform,
Text,
TextInput,
TouchableHighlight,
TouchableOpacity,
View,
} from "react-native";
import PropTypes from "prop-types";
import { defaultColor, defaultTransparent, defaultFont, Style } from "./Style";
import {
colorsToHex,
debounce,
getColorContrast,
isCallable,
isEmpty,
isNumeric,
isTransparentColor,
mergeViewStyle,
parseColor,
} from "./Utils";
/**
* Default constants
*/
export const defaultSpeed = 7;
export const defaultAccelerationDelay = 1000;
export const defaultTypingTime = 500;
/**
* Input Spinner
* @author Marco Cesarato <cesarato.developer@gmail.com>
*/
class InputSpinner extends Component {
/**
* Constructor
* @param props
*/
constructor(props) {
super(props);
// Timers
this.increaseTimer = null;
this.decreaseTimer = null;
this.holdTime = null;
let spinnerStep = this._parseNum(this.props.step);
if (!this.isTypeDecimal() && spinnerStep < 1) {
spinnerStep = 1;
}
let spinnerLongStep = this._parseNum(this.props.longStep);
if (!this.isTypeDecimal() && spinnerLongStep < 1) {
spinnerLongStep = 0;
}
const min = this.props.min != null ? this._parseNum(this.props.min) : null;
const max = this.props.max != null ? this._parseNum(this.props.max) : null;
let initialValue =
this.props.initialValue != null && !isNaN(12)
? this.props.initialValue
: this.props.value;
initialValue = this._parseNum(initialValue);
initialValue = this._withinRange(initialValue, min, max);
// Set debounce
this._debounceSetMax = debounce(
this._setStateMax.bind(this),
this.props.typingTime,
);
this._debounceSetMin = debounce(
this._setStateMin.bind(this),
this.props.typingTime,
);
this._updateValue = debounce((value) => {
this.setState({ value: value });
}, 250);
this.state = {
min: min,
max: max,
value: initialValue,
step: spinnerStep,
longStep: spinnerLongStep,
focused: false,
buttonPress: null,
};
}
/**
* Component did update
* @param prevProps
* @returns {*}
*/
componentDidUpdate(prevProps) {
let min = undefined;
let max = undefined;
// Parse Min
if (this.props.min !== prevProps.min) {
min = this.props.min != null ? this._parseNum(this.props.min) : null;
this.setState({
min
});
}
// Parse Max
if (this.props.max !== prevProps.max) {
max = this.props.max != null ? this._parseNum(this.props.max) : null;
this.setState({
max
});
}
// Parse Value
if (this.props.value !== prevProps.value) {
let newValue = this._parseNum(this.props.value);
newValue = this._withinRange(newValue, min, max);
this._updateValue(newValue);
}
// Parse Step
if (this.props.step !== prevProps.step) {
let spinnerStep = this._parseNum(this.props.step);
if (!this.isTypeDecimal() && spinnerStep < 1) {
spinnerStep = 1;
}
this.setState({ step: spinnerStep });
}
// Parse longStep
if (this.props.longStep !== prevProps.longStep) {
let spinnerLongStep = this._parseNum(this.props.longStep);
if (!this.isTypeDecimal() && spinnerLongStep < 1) {
spinnerLongStep = 0;
}
this.setState({ longStep: spinnerLongStep });
}
}
/**
* Set state to min
* @param callback
* @private
*/
_setStateMin(callback = null) {
return this.setState({ value: "" }, callback);
}
/**
* Set state to max
* @param callback
* @private
*/
_setStateMax(callback = null) {
return this.setState({ value: this.state.max }, callback);
}
/**
* Clear min timer
* @private
*/
_clearMinTimer() {
clearTimeout(this.maxTimer);
this.maxTimer = null;
}
/**
* Clear max timer
* @private
*/
_clearMaxTimer() {
clearTimeout(this.minTimer);
this.minTimer = null;
}
/**
* Clear increase timer
* @private
*/
_clearIncreaseTimer() {
clearTimeout(this.increaseTimer);
this.increaseTimer = null;
}
/**
* Clear decrease timer
* @private
*/
_clearDecreaseTimer() {
clearTimeout(this.decreaseTimer);
this.decreaseTimer = null;
}
/**
* Clear on change timers
* @private
*/
_clearOnChangeTimers() {
this._clearMaxTimer();
this._clearMinTimer();
}
/**
* Clear all timers
* @private
*/
_clearTimers() {
this._clearOnChangeTimers();
this._clearIncreaseTimer();
this._clearDecreaseTimer();
}
/**
* On increase event
* @param number
*/
onIncrease(number) {
if (isCallable(this.props.onIncrease)) {
return this.props.onIncrease(number);
}
return true;
}
/**
* On decrease event
* @param number
*/
onDecrease(number) {
if (isCallable(this.props.onDecrease)) {
return this.props.onDecrease(number);
}
return true;
}
/**
* On max reached event
* @param number
*/
onMax(number) {
if (isCallable(this.props.onMax)) {
this.props.onMax(number);
}
this._resetHoldTime();
}
/**
* On min reached event
* @param number
*/
onMin(number) {
if (isCallable(this.props.onMin)) {
this.props.onMin(number);
}
this._resetHoldTime();
}
/**
* On long press event.
* @param number
*/
onLongPress(number) {
if (isCallable(this.props.onLongPress)) {
this.props.onLongPress(number);
}
}
/**
* Display
* @returns {*}
* @param e
*/
displayFunc(e) {
if (this.props.displayFunc) {
return this.props.displayFunc(e);
}
}
/**
* On value change
* @param value
* @param isPressEvent
*/
async onChange(value, isPressEvent = false) {
const isEmptyValue = isEmpty(value);
this._clearOnChangeTimers();
let num = value;
let parsedNum = value;
if (isEmptyValue) {
num = this.state.min;
}
if (this.props.disabled) return;
const separator = !isEmpty(this.props.decimalSeparator)
? this.props.decimalSeparator
: ".";
if (
String(num).endsWith(separator) &&
!this.getValue().endsWith(separator + "0")
) {
this.decimalInput = true;
}
num = parsedNum = this._parseNum(String(num).replace(/^0+/, "")) || 0;
if (!this.isMinReached(num)) {
if (this.isMaxReached(num)) {
if (this.isMaxReached(num)) {
parsedNum = this.state.max;
if (!isEmptyValue) {
this.maxTimer = this._debounceSetMax();
}
this.onMax(parsedNum);
}
}
} else {
if (!isEmptyValue) {
this.minTimer = this._debounceSetMin();
}
if (isEmptyValue && this.isEmptied()) {
num = parsedNum = null;
} else {
parsedNum = this.state.min;
}
this.onMin(parsedNum);
}
if (isEmptyValue && this.isEmptied()) {
num = parsedNum = null;
} else {
num = this._withinRange(num);
}
if (this.state.value !== num && isCallable(this.props.onChange)) {
const res = await this.props.onChange(parsedNum);
if (!isEmptyValue) {
if (res === false) {
return;
} else if (isNumeric(res)) {
num = this._parseNum(res);
}
}
}
this.setState({ value: num });
}
/**
* On buttons press out
* @param e
*/
onPressOut(e) {
this._resetHoldTime();
}
/**
* On Button Press
* @param buttonDirection
*/
onShowUnderlay(buttonDirection) {
this.setState({ buttonPress: buttonDirection });
}
/**
* On Button Unpress
*/
onHideUnderlay() {
this.setState({ buttonPress: null });
}
/**
* On Submit keyboard
* @returns {*}
* @param e
*/
onSubmit(e) {
if (isCallable(this.props.onSubmit)) {
this.props.onSubmit(this._parseNum(e.nativeEvent.text));
}
}
/**
* On Focus
* @returns {*}
* @param e
*/
onFocus(e) {
if (this.props.onFocus) {
this.props.onFocus(e);
}
this.setState({ focused: true });
}
/**
* On tap input
* @returns {*}
* @param e
*/
onTapInput(e) {
if (this.props.onTapInput) {
this.props.onTapInput(e);
}
}
/**
* On Blur
* @returns {*}
* @param e
*/
onBlur(e) {
if (this.props.onBlur) {
this.props.onBlur(e);
}
this.setState({ focused: false });
}
/**
* On Key Press
* @returns {*}
* @param e
*/
onKeyPress(e) {
if (this.props.onKeyPress) {
this.props.onKeyPress(e);
}
}
/**
* Round number to props precision
* @private
* @param num
* @returns float|int
*/
_roundNum(num) {
if (this.isTypeDecimal()) {
let val = num * Math.pow(10, this.props.precision);
let fraction = Math.round((val - parseInt(val)) * 10) / 10;
if (fraction === -0.5) {
fraction = -0.6;
}
val =
Math.round(parseInt(val) + fraction) /
Math.pow(10, this.props.precision);
return val;
}
return num;
}
/**
* Limit value to be within max and min range
* @private
* @param value
* @param min
* @param max
* @returns float|int
*/
_withinRange(value, min = null, max = null) {
if (min == null && this.state && this.state.min != null) {
min = this.state.min;
}
if (max == null && this.state && this.state.max != null) {
max = this.state.max;
}
if (min != null && value < min) {
value = min;
}
if (max != null && value > max) {
value = max;
}
return value;
}
/**
* Parse number type
* @private
* @param num
* @returns float|int
*/
_parseNum(num) {
num = String(num).replace(
!isEmpty(this.props.decimalSeparator) ? this.props.decimalSeparator : ".",
".",
);
if (this.isTypeDecimal()) {
num = parseFloat(num);
} else {
num = parseInt(num);
}
if (isNaN(num)) {
num = 0;
}
this._roundNum(num);
return num;
}
/**
* Convert value to string
* @returns {string}
*/
getValue() {
let value = this.state.value;
if (isEmpty(value)) {
return "";
}
if (this.isTypeDecimal() && this.decimalInput) {
this.decimalInput = false;
value = this._parseNum(value).toFixed(1).replace(/0+$/, "");
} else if (this.isTypeDecimal()) {
value = String(
this._parseNum(this._parseNum(value).toFixed(this.props.precision)),
);
} else {
value = String(this._parseNum(value));
}
let hasPlaceholder = value === "0" && !isEmpty(this.props.placeholder);
return hasPlaceholder
? ""
: value.replace(
".",
!isEmpty(this.props.decimalSeparator)
? this.props.decimalSeparator
: ".",
);
}
/**
* Get Placeholder
* @returns {*}
*/
getPlaceholder() {
if (!isEmpty(this.props.placeholder)) {
return this.props.placeholder;
} else if (isEmpty(this.state.value) && this.isEmptied()) {
return "";
} else {
return String(this.state.min);
}
}
/**
* Get Placeholder
* @returns {*}
*/
getPlaceholderColor() {
if (this.props.placeholderTextColor) {
return this.props.placeholderTextColor;
}
let textColor = this._getInputTextColor();
let parse = parseColor(textColor);
parse[3] = Math.round(0.6 * 255);
return colorsToHex(parse);
}
/**
* Get Type
* @returns {String}
*/
getType() {
let type = this.props.type;
if (this.props.type != null) {
type = this.props.type;
}
return String(type).toLowerCase();
}
/**
* Detect if type is decimal
* @returns {boolean}
*/
isTypeDecimal() {
let type = this.getType();
return (
type === "float" ||
type === "double" ||
type === "decimal" ||
type === "real"
);
}
/**
* Update holding time
* @private
*/
_startHoldTime() {
this.holdTime = new Date().getTime();
}
/**
* Get the holding time
* @private
*/
_getHoldTime() {
if (isEmpty(this.holdTime)) {
return 0;
}
let now = new Date().getTime();
return now - this.holdTime;
}
/**
* Reset holding time
* @private
*/
_resetHoldTime() {
this.holdTime = null;
this._clearTimers();
}
/**
* Find the interval between changing values after a button has been held for a certain amount of time
* @returns {number}
* @author Tom Hardern <https://gist.github.com/taeh98/f709451457400818094d802cd33694d5>
* @private
*/
_getHoldChangeInterval() {
const minInterval = 10;
var time = (10 - Math.log(this.props.speed * this._getHoldTime())) * 100;
return time < minInterval ? minInterval : time;
}
/**
* On hold increase
* @param event
* @returns {Promise<void>}
*/
async increaseHold(event) {
this.increase(event, true);
}
/**
* Increase
* @param event
* @param isLongPress
* @returns {Promise<void>}
*/
async increase(event, isLongPress = false) {
if (this._isDisabledButtonRight()) return;
let currentValue = this._parseNum(this.state.value);
let num =
currentValue +
this._parseNum(
isLongPress && this.state.longStep > 0
? this.state.longStep
: this.state.step,
);
if (isLongPress && this.state.longStep > 0) {
num = Math.round(num / this.state.longStep) * this.state.longStep;
}
if (this.isTypeDecimal()) {
num = Number(num.toFixed(this.props.precision));
}
if (
this.isMaxReached(currentValue) &&
!this.isEmptied() &&
this.isContinuos()
) {
// Continuity mode
num = this.state.min;
} else if (this.isMaxReached(currentValue)) {
this.onMax(currentValue);
return;
}
const res = await this.onIncrease(num);
if (res === false) {
return;
} else if (isNumeric(res)) {
num = this._parseNum(res);
}
let wait = this._getHoldChangeInterval();
if (!isLongPress && this.increaseTimer === null) {
this._startHoldTime();
wait = this.props.accelerationDelay;
} else if (isLongPress) {
this.onLongPress(num);
}
if (isLongPress) {
this.increaseTimer = setTimeout(
this.increase.bind(this, event, true),
wait,
);
}
this.onChange(num, true);
}
/**
* On hold decrease
* @param event
* @returns {Promise<void>}
*/
async decreaseHold(event) {
this.decrease(event, true);
}
/**
* Decrease
* @param event
* @param isLongPress
* @returns {Promise<void>}
*/
async decrease(event, isLongPress = false) {
if (this._isDisabledButtonLeft()) return;
let currentValue = this._parseNum(this.state.value);
let num =
currentValue -
this._parseNum(
isLongPress && this.state.longStep > 0
? this.state.longStep
: this.state.step,
);
if (isLongPress && this.state.longStep > 0) {
num = Math.round(num / this.state.longStep) * this.state.longStep;
}
if (this.isTypeDecimal()) {
num = Number(num.toFixed(this.props.precision));
}
if (
this.isMinReached(currentValue) &&
!this.isEmptied() &&
this.isContinuos()
) {
// Continuity mode
num = this.state.max;
} else if (this.isMinReached(currentValue)) {
this.onMin(currentValue);
return;
}
const res = await this.onDecrease(num);
if (res === false) {
return;
} else if (isNumeric(res)) {
num = this._parseNum(res);
}
let wait = this._getHoldChangeInterval();
if (!isLongPress && this.decreaseTimer === null) {
this._startHoldTime();
wait = this.props.accelerationDelay;
} else if (isLongPress) {
this.onLongPress(num);
}
if (isLongPress) {
this.decreaseTimer = setTimeout(
this.decrease.bind(this, event, true),
wait,
);
}
this.onChange(num, true);
}
/**
* Max is reached
* @param num
* @returns {boolean}
*/
isMaxReached(num = null) {
if (this.state.max != null) {
if (num == null) {
num = this.state.value;
}
return num >= this.state.max;
}
return false;
}
/**
* Min is reached
* @param num
* @returns {boolean}
*/
isMinReached(num = null) {
if (this.state.min != null) {
if (num == null) {
num = this.state.value;
}
return num <= this.state.min;
}
return false;
}
/**
* Blur
*/
blur() {
this.textInput.blur();
}
/**
* Focus
*/
focus() {
this.textInput.focus();
}
/**
* Clear
*/
clear() {
this.textInput.clear();
}
/**
* Is text input editable
* @returns {boolean|Boolean}
*/
isEditable() {
return (
(this.props.disabled !== true || this.props.disabled != null) &&
this.props.editable !== false
);
}
/**
* If continuity mode enabled
* @returns {boolean|Boolean}
*/
isContinuos() {
return this.props.continuity !== false;
}
/**
* If input can be empty
* @returns {boolean|Boolean}
*/
isEmptied() {
return this.props.emptied !== false;
}
/**
* Is text input focused
* @returns {boolean|Boolean}
*/
isFocused() {
return this.state.focus !== false;
}
/**
* Is left button disabled
* @returns {Boolean}
* @private
*/
_isDisabledButtonLeft() {
return (
this.props.disabled !== false || this.props.buttonLeftDisabled !== false
);
}
/**
* Is right button disabled
* @returns {Boolean}
* @private
*/
_isDisabledButtonRight() {
return (
this.props.disabled !== false || this.props.buttonRightDisabled !== false
);
}
/**
* Is right button pressed
* @returns {boolean}
* @private
*/
_isRightButtonPressed() {
return this.state.buttonPress === "right";
}
/**
* Is left button pressed
* @returns {boolean}
* @private
*/
_isLeftButtonPressed() {
return this.state.buttonPress === "left";
}
/**
* Get keyboard type
* @returns {string}
* @private
*/
_getKeyboardType() {
// Keyboard type
let keyboardType = "number-pad";
if (this.isTypeDecimal()) {
keyboardType = "decimal-pad";
}
return keyboardType;
}
/**
* Get auto capitalize
* @returns {string}
* @private
*/
_getAutoCapitalize() {
let autoCapitalize = this.props.autoCapitalize
? this.props.autoCapitalize
: "none";
if (this.isTypeDecimal()) {
autoCapitalize = "words";
}
return autoCapitalize;
}
/**
* Get main color
* @returns {String|*}
* @private
*/
_getMainColor() {
let color = this.props.color;
if (this.props.colorAsBackground) {
color = defaultTransparent;
} else if (isTransparentColor(color)) {
color = defaultTransparent;
}
return color;
}
/**
* Get button color
* @returns {String|*}
* @private
*/
_getColor() {
const color = this._getMainColor();
return this.isMaxReached()
? this._getColorMax()
: this.isMinReached()
? this._getColorMin()
: color;
}
/**
* Get min color
* @returns {String}
* @private
*/
_getColorMin() {
if (!this.props.colorMin) {
return this.props.color;
}
return this.props.colorMin;
}
/**
* Get max color
* @returns {String}
* @private
*/
_getColorMax() {
if (!this.props.colorMax) {
return this.props.color;
}
return this.props.colorMax;
}
/**
* Get color on button press
* @returns {String|*}
* @private
*/
_getColorPress() {
const color = this.props.colorAsBackground
? defaultTransparent
: this.props.color;
return this.props.colorPress !== defaultColor
? this.props.colorPress
: color;
}
/**
* Get color text on button press
* @returns {string}
* @private
*/
_getColorPressText() {
const color = this.props.colorAsBackground
? this._getColorBackground()
: this._getColorPress();
const pressColor = this.props.buttonPressTextColor
? this.props.buttonPressTextColor
: this._getColorText();
let textColor =
this.props.buttonPressTextColor !== this.props.buttonTextColor
? pressColor
: "auto";
if (String(textColor).toLowerCase().trim() === "auto") {
textColor = getColorContrast(color);
}
return textColor;
}
/**
* Get color text on button
* @returns {string}
* @private
*/
_getColorText() {
const color = this.props.colorAsBackground
? this._getColorBackground()
: this._getColor();
let textColor =
this._getColor() !== this._getMainColor()
? "auto"
: this.props.buttonTextColor
? this.props.buttonTextColor
: "auto";
if (String(textColor).toLowerCase().trim() === "auto") {
textColor = getColorContrast(color);
}
return textColor;
}
/**
* Get left button color
* @returns {string}
* @private
*/
_getColorLeftButton() {
const color = this._getColor();
return this.props.colorLeft !== defaultColor ? this.props.colorLeft : color;
}
/**
* Get right button color
* @returns {string}
* @private
*/
_getColorRightButton() {
const color = this._getColor();
return this.props.colorRight !== defaultColor
? this.props.colorRight
: color;
}
/**
* Get background color
* @returns {string|*}
* @private
*/
_getColorBackground() {
let color = this.props.color;
let background = this.props.background;
if (isTransparentColor(color)) {
color = defaultTransparent;
}
if (isTransparentColor(background)) {
background = defaultTransparent;
}
return this.props.colorAsBackground
? this.isMaxReached()
? this._getColorMax()
: this.isMinReached()
? this._getColorMin()
: color
: background;
}
/**
* Get container style
* @returns {*[]}
* @private
*/
_getContainerStyle() {
const backgroundColor = this._getColorBackground();
return [
Style.container,
{
minHeight: this.props.height,
width: this.props.width,
backgroundColor: backgroundColor,
},
this.props.showBorder
? { borderWidth: 0.5, borderColor: this._getColor() }
: {},
this.props.shadow ? Style.containerShadow : {},
this.props.rounded ? { borderRadius: this.props.height / 2 } : {},
this.props.style,
];
}
/**
* Get input text color
* @returns {string|*}
* @private
*/
_getInputTextColor() {
const backgroundColor = this._getColorBackground();
return this.props.textColor
? this.props.textColor
: getColorContrast(backgroundColor);
}
/**
* Get input text style
* @returns {*[]}
* @private
*/
_getInputTextStyle() {
const backgroundColor = this._getColorBackground();
return [
Style.numberText,
{
color: this._getInputTextColor(),
fontSize: this.props.fontSize,
fontFamily: this.props.fontFamily,
backgroundColor: backgroundColor,
height: this.props.height,
},
this.props.showBorder
? { borderWidth: 0.5, borderColor: this._getColor() }
: {},
this.props.inputStyle,
];
}
/**
* Get button style
* @returns {*}
* @private
*/
_getStyleButton() {
const size = this.props.height;
return {
height: size,
width: size,
};
}
/**
* Get button pressed style
* @returns {Object}
* @private
*/
_getStyleButtonPress() {
return isEmpty(this.props.buttonPressStyle)
? this.props.buttonStyle
: this.props.buttonPressStyle;
}
/**
* Get button text style
* @returns {*[]}
* @private
*/
_getStyleButtonText() {
return [
Style.buttonText,
{
fontSize: this.props.buttonFontSize,
fontFamily: this.props.buttonFontFamily,
lineHeight: this.props.height,
},
this.props.buttonTextStyle ? this.props.buttonTextStyle : {},
];
}
/**
* Get left button text style
* @returns {*[]}
* @private
*/
_getStyleLeftButtonText() {
return [
Style.buttonText,
this._getStyleButtonText(),
{
color: this._isLeftButtonPressed()
? this._getColorPressText()
: this._getColorText(),
},
this._isLeftButtonPressed() ? this.props.buttonPressTextStyle : {},
];
}
/**
* Get right button text style
* @returns {*[]}
* @private
*/
_getStyleRightButtonText() {
return [
Style.buttonText,
this._getStyleButtonText(),
{
color: this._isRightButtonPressed()
? this._getColorPressText()
: this._getColorText(),
},
this._isRightButtonPressed() ? this.props.buttonPressTextStyle : {},
];
}
/**
* Render left button element
* @returns {*}
* @private
*/
_renderLeftButtonElement() {
if (this.props.buttonLeftImage) {
return this.props.buttonLeftImage;
} else if (this._isLeftButtonPressed() && this.props.buttonPressLeftImage) {
return this.props.buttonPressLeftImage;
} else {
const text =
this.props.arrows !== false
? "❮"
: this.props.buttonLeftText
? this.props.buttonLeftText
: "-";
return <Text style={this._getStyleLeftButtonText()}>{text}</Text>;
}
}
/**
* Render right button element
* @returns {*}
* @private
*/
_renderRightButtonElement() {
if (this.props.buttonRightImage) {
return this.props.buttonRightImage;
} else if (
this._isRightButtonPressed() &&
this.props.buttonPressRightImage
) {
return this.props.buttonPressRightImage;
} else {
const text =
this.props.arrows !== false
? "❯"
: this.props.buttonRightText
? this.props.buttonRightText
: "+";
return <Text style={this._getStyleRightButtonText()}>{text}</Text>;
}
}
/**
* Render left button
* @returns {*}
* @private
*/
_renderLeftButton() {
const colorLeft = this._getColorLeftButton();
const buttonStyle = mergeViewStyle(
this._isLeftButtonPressed()
? this._getStyleButtonPress()
: this.props.buttonStyle,
[
this._getStyleButton(),
{
borderColor: this.props.showBorder ? colorLeft : "transparent",
backgroundColor: colorLeft,
},
this.props.rounded ? Style.buttonRounded : Style.buttonLeft,
],
);
return (
<TouchableHighlight
activeOpacity={this.props.activeOpacity}
underlayColor={this._getColorPress()}
onHideUnderlay={this.onHideUnderlay.bind(this)}
onShowUnderlay={this.onShowUnderlay.bind(this, "left")}
disabled={this._isDisabledButtonLeft()}
style={buttonStyle}
onPressIn={this.decrease.bind(this)}
onPressOut={this.onPressOut.bind(this)}
onLongPress={this.props.hasTapHold ? this.decreaseHold.bind(this) : undefined}
delayLongPress={this.props.accelerationDelay}
{...this.props.leftButtonProps}>
{this._renderLeftButtonElement()}
</TouchableHighlight>
);
}
/**
* Render right button
* @returns {*}
* @private
*/
_renderRightButton() {
const colorRight = this._getColorRightButton();
const buttonStyle = mergeViewStyle(
this._isRightButtonPressed()
? this._getStyleButtonPress()
: this.props.buttonStyle,
[
this._getStyleButton(),
{
borderColor: this.props.showBorder ? colorRight : "transparent",
backgroundColor: colorRight,
},
this.props.rounded ? Style.buttonRounded : Style.buttonRight,
],
);
return (
<TouchableHighlight
activeOpacity={this.props.activeOpacity}
underlayColor={this._getColorPress()}
onHideUnderlay={this.onHideUnderlay.bind(this)}
onShowUnderlay={this.onShowUnderlay.bind(this, "right")}
disabled={this._isDisabledButtonRight()}
style={buttonStyle}
onPressIn={this.increase.bind(this)}
onPressOut={this.onPressOut.bind(this)}
onLongPress={this.props.hasTapHold ? this.increaseHold.bind(this) : undefined}
delayLongPress={this.props.accelerationDelay}
{...this.props.rightButtonProps}>
{this._renderRightButtonElement()}
</TouchableHighlight>
);
}
/**
* Render
* @returns {*}
*/
render() {
return (
<View style={this._getContainerStyle()} {...this.props.containerProps}>
{this._renderLeftButton()}
{this.props.prepend}
{(this.props.editable === false || this.props.editable == null) && <TouchableOpacity style={{ height: this.props.height, justifyContent: "center" }} onPress={this.onTapInput.bind(this)} activeOpacity={1}>
<Text
style={[this.props.inputStyle, { textAlign: "center" }]}
{...this.props.inputProps}
>{this.props.displayFunc != null ? this.displayFunc(this.getValue()) : (this.getValue() == null || this.getValue() == "" ? this.getPlaceholder() : this.getValue())}</Text>
</TouchableOpacity>}
{this.props.editable === true && <TextInput
ref={(input) => (this.textInput = input)}
style={this._getInputTextStyle()}
value={this.getValue()}
placeholder={this.getPlaceholder()}
placeholderTextColor={this.getPlaceholderColor()}
selectionColor={this.props.selectionColor}
selectTextOnFocus={this.props.selectTextOnFocus}
returnKeyType={this.props.returnKeyType}
returnKeyLabel={this.props.returnKeyLabel}
autoFocus={this.props.autoFocus}
autoCapitalize={this._getAutoCapitalize()} // Bug fix for Samsung Keyboard
editable={this.isEditable()}
maxLength={this.props.maxLength}
onKeyPress={this.onKeyPress.bind(this)}
onFocus={this.onFocus.bind(this)}
onBlur={this.onBlur.bind(this)}
keyboardType={this._getKeyboardType()}
onChangeText={this.onChange.bind(this)}
onSubmitEditing={this.onSubmit.bind(this)}
{...this.props.inputProps}
/>}
{this.props.children}
{this.props.append}
{this._renderRightButton()}
</View>
);
}
}
InputSpinner.propTypes = {
type: PropTypes.string,
skin: PropTypes.string,
min: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
max: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
initialValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
step: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
longStep: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
precision: PropTypes.number,
shadow: PropTypes.bool,
rounded: PropTypes.bool,
activeOpacity: PropTypes.number,
color: PropTypes.string,
colorPress: PropTypes.string,
colorRight: PropTypes.string,
colorLeft: PropTypes.string,
colorMax: PropTypes.string,
colorMin: PropTypes.string,
colorAsBackground: PropTypes.bool,
background: PropTypes.string,
textColor: PropTypes.string,
arrows: PropTypes.bool,
showBorder: PropTypes.bool,
fontSize: PropTypes.number,
fontFamily: PropTypes.string,
buttonFontSize: PropTypes.number,
buttonFontFamily: PropTypes.string,
buttonTextColor: PropTypes.string,
maxLength: PropTypes.number,
disabled: PropTypes.bool,
editable: PropTypes.bool,
autoFocus: PropTypes.bool,
selectTextOnFocus: PropTypes.bool,
placeholder: PropTypes.string,
placeholderTextColor: PropTypes.string,
selectionColor: PropTypes.string,
returnKeyLabel: PropTypes.string,
returnKeyType: PropTypes.string,
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
displayFunc: PropTypes.func,
onChange: PropTypes.func,
onFocus: PropTypes.func,
onTapInput: PropTypes.func,
onBlur: PropTypes.func,
onKeyPress: PropTypes.func,
onMin: PropTypes.func,
onMax: PropTypes.func,
onIncrease: PropTypes.func,
onDecrease: PropTypes.func,
onSubmit: PropTypes.func,
onLongPress: PropTypes.func,
accelerationDelay: PropTypes.number,
speed: PropTypes.number,
emptied: PropTypes.bool,
continuity: PropTypes.bool,
typingTime: PropTypes.number,
hasTapHold: PropTypes.bool,
buttonLeftDisabled: PropTypes.bool,
buttonRightDisabled: PropTypes.bool,
buttonLeftText: PropTypes.string,
buttonRightText: PropTypes.string,
buttonLeftImage: PropTypes.element,
buttonRightImage: PropTypes.element,
buttonPressLeftImage: PropTypes.element,
buttonPressRightImage: PropTypes.element,
buttonStyle: PropTypes.oneOfType([
PropTypes.object,
PropTypes.array,
PropTypes.number,
PropTypes.string,
]),
buttonTextStyle: PropTypes.oneOfType([
PropTypes.object,
PropTypes.array,
PropTypes.number,
PropTypes.string,
]),
buttonPressStyle: PropTypes.oneOfType([
PropTypes.object,
PropTypes.array,
PropTypes.number,
PropTypes.string,
]),
buttonPressTextStyle: PropTypes.oneOfType([
PropTypes.object,
PropTypes.array,
PropTypes.number,
PropTypes.string,
]),
inputStyle: PropTypes.oneOfType([
PropTypes.object,
PropTypes.array,
PropTypes.number,
PropTypes.string,
]),
style: PropTypes.oneOfType([
PropTypes.object,
PropTypes.array,
PropTypes.number,
PropTypes.string,
]),
append: PropTypes.element,
prepend: PropTypes.element,
decimalSeparator: PropTypes.string,
containerProps: PropTypes.object,
inputProps: PropTypes.object,
leftButtonProps: PropTypes.object,
rightButtonProps: PropTypes.object,
};
InputSpinner.defaultProps = {
type: "int",
skin: null,
min: 0,
max: null,
value: 0,
initialValue: null,
step: 1,
longStep: 0,
precision: 2,
rounded: true,
shadow: false,
activeOpacity: 0.85,
color: defaultColor,
colorPress: defaultColor,
colorRight: defaultColor,
colorLeft: defaultColor,
colorAsBackground: false,
background: "transparent",
textColor: null,
arrows: false,
showBorder: false,
fontSize: 14,
fontFamily: defaultFont,
buttonFontSize: 25,
buttonFontFamily: defaultFont,
buttonTextColor: null,
buttonPressTextColor: null,
maxLength: null,
disabled: false,
editable: true,
autoFocus: false,
selectTextOnFocus: null,
selectionColor: null,
returnKeyLabel: null,
returnKeyType: null,
width: "auto",
height: 50,
accelerationDelay: defaultAccelerationDelay,
speed: defaultSpeed,
emptied: false,
continuity: false,
typingTime: defaultTypingTime,
buttonLeftDisabled: false,
buttonRightDisabled: false,
buttonLeftText: null,
buttonRightText: null,
buttonStyle: null,
buttonTextStyle: null,
buttonPressStyle: null,
buttonPressTextStyle: null,
inputStyle: null,
style: null,
decimalSeparator: ".",
containerProps: null,
inputProps: null,
leftButtonProps: null,
rightButtonProps: null,
};
// Export
export default (props) => {
const finalProps = {...props };
return <InputSpinner {...finalProps} />;
};