react-number-format
Advanced tools
Comparing version 2.0.0-alpha5 to 2.0.0-beta1
/*! | ||
* react-number-format - 2.0.0-alpha5 | ||
* react-number-format - 2.0.0-beta1 | ||
* Author : Sudhanshu Yadav | ||
@@ -100,2 +100,4 @@ * Copyright (c) 2016,2017 to Sudhanshu Yadav - ignitersworld.com , released under the MIT license. | ||
* 10. isAllowed props to validate input and block if returns false | ||
* 11. Round to precision for passed value | ||
* 12. It should always move cursor to type area ignoring prefix and suffix | ||
*/ | ||
@@ -115,2 +117,6 @@ | ||
/** | ||
* limit decimal numbers to given precision | ||
* Not used .fixedTo because that will break with big numbers | ||
*/ | ||
function limitToPrecision(numStr, precision) { | ||
@@ -124,2 +130,21 @@ var str = ''; | ||
/** | ||
* This method is required to round prop value to given precision. | ||
* Not used .round or .fixedTo because that will break with big numbers | ||
*/ | ||
function roundToPrecision(numStr, precision) { | ||
var numberParts = numStr.split('.'); | ||
var roundedDecimalParts = parseFloat('0.' + (numberParts[1] || '0')).toFixed(precision).split('.'); | ||
var intPart = numberParts[0].split('').reverse().reduce(function (roundedStr, current, idx) { | ||
if (roundedStr.length > idx) { | ||
return (Number(roundedStr[0]) + Number(current)).toString() + roundedStr.substring(1, roundedStr.length); | ||
} | ||
return current + roundedStr; | ||
}, roundedDecimalParts[0]); | ||
var decimalPart = roundedDecimalParts[1]; | ||
return intPart + (decimalPart ? '.' + decimalPart : ''); | ||
} | ||
function omit(obj, keyMaps) { | ||
@@ -146,2 +171,3 @@ var filteredObj = {}; | ||
onKeyDown: _propTypes2.default.func, | ||
onMouseUp: _propTypes2.default.func, | ||
onChange: _propTypes2.default.func, | ||
@@ -155,2 +181,4 @@ type: _propTypes2.default.oneOf(['text', 'tel']), | ||
decimalSeparator: '.', | ||
prefix: '', | ||
suffix: '', | ||
allowNegative: true, | ||
@@ -160,2 +188,3 @@ type: 'text', | ||
onKeyDown: noop, | ||
onMouseUp: noop, | ||
isAllowed: function isAllowed() { | ||
@@ -180,2 +209,3 @@ return true; | ||
_this.onKeyDown = _this.onKeyDown.bind(_this); | ||
_this.onMouseUp = _this.onMouseUp.bind(_this); | ||
return _this; | ||
@@ -213,13 +243,23 @@ } | ||
}, { | ||
key: 'getFloatValue', | ||
value: function getFloatValue(num) { | ||
var decimalSeparator = this.props.decimalSeparator; | ||
key: 'getFloatString', | ||
value: function getFloatString(num, props) { | ||
props = props || this.props; | ||
return parseFloat(num.replace(decimalSeparator, '.')) || 0; | ||
var _getSeparators = this.getSeparators(props), | ||
decimalSeparator = _getSeparators.decimalSeparator, | ||
thousandSeparator = _getSeparators.thousandSeparator; | ||
return num.replace(new RegExp(escapeRegExp(thousandSeparator || ''), 'g'), '').replace(decimalSeparator, '.'); | ||
} | ||
}, { | ||
key: 'getFloatValue', | ||
value: function getFloatValue(num, props) { | ||
props = props || this.props; | ||
return parseFloat(this.getFloatString(num, props)) || 0; | ||
} | ||
}, { | ||
key: 'optimizeValueProp', | ||
value: function optimizeValueProp(props) { | ||
var _getSeparators = this.getSeparators(props), | ||
decimalSeparator = _getSeparators.decimalSeparator; | ||
var _getSeparators2 = this.getSeparators(props), | ||
decimalSeparator = _getSeparators2.decimalSeparator; | ||
@@ -237,7 +277,17 @@ var decimalPrecision = props.decimalPrecision, | ||
value = this.removePrefixAndSuffix(isNumber ? value : this.getFloatString(value, props), props); | ||
//round off value | ||
if (typeof decimalPrecision === 'number') value = roundToPrecision(value, decimalPrecision); | ||
//correct decimal separator | ||
if (decimalSeparator && isNumber) { | ||
if (decimalSeparator) { | ||
value = value.replace('.', decimalSeparator); | ||
} | ||
//throw error if value has two decimal seperators | ||
if (value.split(decimalSeparator).length > 2) { | ||
throw new Error('\n Wrong input for value props.\n\n More than one decimalSeparator found\n '); | ||
} | ||
//if decimalPrecision is 0 remove decimalNumbers | ||
@@ -249,2 +299,30 @@ if (decimalPrecision === 0) return value.split(decimalSeparator)[0]; | ||
}, { | ||
key: 'removePrefixAndSuffix', | ||
value: function removePrefixAndSuffix(val, props) { | ||
var format = props.format, | ||
prefix = props.prefix, | ||
suffix = props.suffix; | ||
//remove prefix and suffix | ||
if (!format && val) { | ||
var isNegative = val[0] === '-'; | ||
//remove negation sign | ||
if (isNegative) val = val.substring(1, val.length); | ||
//remove prefix | ||
val = prefix && val.indexOf(prefix) === 0 ? val.substring(prefix.length, val.length) : val; | ||
//remove suffix | ||
var suffixLastIndex = val.lastIndexOf(suffix); | ||
val = suffix && suffixLastIndex !== -1 && suffixLastIndex === val.length - suffix.length ? val.substring(0, suffixLastIndex) : val; | ||
//add negation sign back | ||
if (isNegative) val = '-' + val; | ||
} | ||
return val; | ||
} | ||
}, { | ||
key: 'getSeparators', | ||
@@ -280,4 +358,4 @@ value: function getSeparators(props) { | ||
var _getSeparators2 = this.getSeparators(), | ||
decimalSeparator = _getSeparators2.decimalSeparator; | ||
var _getSeparators3 = this.getSeparators(), | ||
decimalSeparator = _getSeparators3.decimalSeparator; | ||
@@ -327,8 +405,20 @@ return new RegExp('\\d' + (decimalSeparator && decimalPrecision !== 0 && !ignoreDecimalSeparator && !format ? '|' + escapeRegExp(decimalSeparator) : ''), g ? 'g' : undefined); | ||
} | ||
/* This keeps the caret within typing area so people can't type in between prefix or suffix */ | ||
}, { | ||
key: 'correctCaretPosition', | ||
value: function correctCaretPosition(value, caretPos) { | ||
var _props4 = this.props, | ||
prefix = _props4.prefix, | ||
suffix = _props4.suffix; | ||
return Math.min(Math.max(caretPos, prefix.length), value.length - suffix.length); | ||
} | ||
}, { | ||
key: 'formatWithPattern', | ||
value: function formatWithPattern(str) { | ||
var _props4 = this.props, | ||
format = _props4.format, | ||
mask = _props4.mask; | ||
var _props5 = this.props, | ||
format = _props5.format, | ||
mask = _props5.mask; | ||
@@ -357,13 +447,14 @@ if (!format) return str; | ||
value: function formatInput(val) { | ||
var _props5 = this.props, | ||
prefix = _props5.prefix, | ||
suffix = _props5.suffix, | ||
mask = _props5.mask, | ||
format = _props5.format, | ||
allowNegative = _props5.allowNegative, | ||
decimalPrecision = _props5.decimalPrecision; | ||
var props = this.props, | ||
removePrefixAndSuffix = this.removePrefixAndSuffix; | ||
var prefix = props.prefix, | ||
suffix = props.suffix, | ||
mask = props.mask, | ||
format = props.format, | ||
allowNegative = props.allowNegative, | ||
decimalPrecision = props.decimalPrecision; | ||
var _getSeparators3 = this.getSeparators(), | ||
thousandSeparator = _getSeparators3.thousandSeparator, | ||
decimalSeparator = _getSeparators3.decimalSeparator; | ||
var _getSeparators4 = this.getSeparators(), | ||
thousandSeparator = _getSeparators4.thousandSeparator, | ||
decimalSeparator = _getSeparators4.decimalSeparator; | ||
@@ -381,2 +472,3 @@ var maskPattern = format && typeof format == 'string' && !!mask; | ||
//check if it has negative numbers | ||
if (allowNegative && !format) { | ||
@@ -389,2 +481,5 @@ // Check number has '-' value | ||
//remove prefix and suffix | ||
val = removePrefixAndSuffix(val, props); | ||
var valMatch = val && val.match(numRegex); | ||
@@ -437,3 +532,3 @@ | ||
return { | ||
value: (hasNegative && !removeNegative ? '-' : '') + formattedValue.match(numRegex).join(''), | ||
value: (hasNegative && !removeNegative ? '-' : '') + removePrefixAndSuffix(formattedValue, props).match(numRegex).join(''), | ||
formattedValue: formattedValue | ||
@@ -443,5 +538,7 @@ }; | ||
}, { | ||
key: 'getCursorPosition', | ||
value: function getCursorPosition(inputValue, formattedValue, cursorPos) { | ||
var numRegex = this.getNumberRegex(); | ||
key: 'getCaretPosition', | ||
value: function getCaretPosition(inputValue, formattedValue, caretPos) { | ||
var numRegex = this.getNumberRegex(true); | ||
var inputNumber = (inputValue.match(numRegex) || []).join(''); | ||
var formattedNumber = (formattedValue.match(numRegex) || []).join(''); | ||
var j = void 0, | ||
@@ -452,6 +549,15 @@ i = void 0; | ||
for (i = 0; i < cursorPos; i++) { | ||
if (!inputValue[i].match(numRegex) && inputValue[i] !== formattedValue[j]) continue; | ||
if (inputValue[i] === '0' && (formattedValue[j] || '').match(numRegex) && formattedValue[j] !== '0') continue; | ||
while (inputValue[i] !== formattedValue[j] && j < formattedValue.length) { | ||
for (i = 0; i < caretPos; i++) { | ||
var currentInputChar = inputValue[i]; | ||
var currentFormatChar = formattedValue[j] || ''; | ||
//no need to increase new cursor position if formatted value does not have those characters | ||
//case inputValue = 1a23 and formattedValue = 123 | ||
if (!currentInputChar.match(numRegex) && currentInputChar !== currentFormatChar) continue; | ||
//When we are striping out leading zeros maintain the new cursor position | ||
//Case inputValue = 00023 and formattedValue = 23; | ||
if (currentInputChar === '0' && currentFormatChar.match(numRegex) && currentFormatChar !== '0' && inputNumber.length !== formattedNumber.length) continue; | ||
//we are not using currentFormatChar because j can change here | ||
while (currentInputChar !== formattedValue[j] && !(formattedValue[j] || '').match(numRegex) && j < formattedValue.length) { | ||
j++; | ||
@@ -461,2 +567,5 @@ }j++; | ||
//correct caret position if its outsize of editable area | ||
j = this.correctCaretPosition(formattedValue, j); | ||
return j; | ||
@@ -480,10 +589,14 @@ } | ||
/*Max of selectionStart and selectionEnd is taken for the patch of pixel and other mobile device cursor bug*/ | ||
/*Max of selectionStart and selectionEnd is taken for the patch of pixel and other mobile device caret bug*/ | ||
var currentCursorPosition = Math.max(el.selectionStart, el.selectionEnd); | ||
var currentCaretPosition = Math.max(el.selectionStart, el.selectionEnd); | ||
var cursorPos = this.getCursorPosition(inputValue, formattedValue, currentCursorPosition); | ||
var valueObj = { | ||
formattedValue: formattedValue, | ||
value: value, | ||
floatValue: this.getFloatValue(value) | ||
}; | ||
if (!isAllowed(formattedValue, value, this.getFloatValue(value))) { | ||
if (!isAllowed(valueObj)) { | ||
formattedValue = lastValue; | ||
@@ -495,4 +608,7 @@ } | ||
//get the caret position | ||
var caretPos = this.getCaretPosition(inputValue, formattedValue, currentCaretPosition); | ||
//set caret position | ||
this.setPatchedCaretPosition(el, cursorPos, formattedValue); | ||
this.setPatchedCaretPosition(el, caretPos, formattedValue); | ||
@@ -502,3 +618,3 @@ //change the state | ||
this.setState({ value: formattedValue }, function () { | ||
props.onChange(e, value); | ||
props.onChange(e, valueObj); | ||
}); | ||
@@ -513,6 +629,9 @@ } | ||
var el = e.target; | ||
var selectionStart = el.selectionStart, | ||
selectionEnd = el.selectionEnd, | ||
var selectionEnd = el.selectionEnd, | ||
value = el.value; | ||
var decimalPrecision = this.props.decimalPrecision; | ||
var selectionStart = el.selectionStart; | ||
var _props6 = this.props, | ||
decimalPrecision = _props6.decimalPrecision, | ||
prefix = _props6.prefix, | ||
suffix = _props6.suffix; | ||
var key = e.key; | ||
@@ -522,16 +641,23 @@ | ||
var negativeRegex = new RegExp('-'); | ||
//Handle backspace and delete against non numerical/decimal characters | ||
if (selectionEnd - selectionStart === 0) { | ||
if (key === 'Delete' && !numRegex.test(value[selectionStart]) && !negativeRegex.test(value[selectionStart])) { | ||
e.preventDefault(); | ||
var nextCursorPosition = selectionStart; | ||
while (!numRegex.test(value[nextCursorPosition]) && nextCursorPosition < value.length) { | ||
nextCursorPosition++; | ||
}this.setPatchedCaretPosition(el, nextCursorPosition, value); | ||
if (selectionStart === selectionEnd) { | ||
var newCaretPosition = selectionStart; | ||
if (key === 'ArrowLeft' || key === 'ArrowRight') { | ||
selectionStart += key === 'ArrowLeft' ? -1 : +1; | ||
newCaretPosition = this.correctCaretPosition(value, selectionStart); | ||
} else if (key === 'Delete' && !numRegex.test(value[selectionStart]) && !negativeRegex.test(value[selectionStart])) { | ||
while (!numRegex.test(value[newCaretPosition]) && newCaretPosition < value.length - suffix.length) { | ||
newCaretPosition++; | ||
} | ||
} else if (key === 'Backspace' && !numRegex.test(value[selectionStart - 1]) && !negativeRegex.test(value[selectionStart - 1])) { | ||
while (!numRegex.test(value[newCaretPosition - 1]) && newCaretPosition > prefix.length) { | ||
newCaretPosition--; | ||
} | ||
} | ||
if (newCaretPosition !== selectionStart) { | ||
e.preventDefault(); | ||
var prevCursorPosition = selectionStart; | ||
while (!numRegex.test(value[prevCursorPosition - 1]) && prevCursorPosition > 0) { | ||
prevCursorPosition--; | ||
}this.setPatchedCaretPosition(el, prevCursorPosition, value); | ||
this.setPatchedCaretPosition(el, newCaretPosition, value); | ||
} | ||
@@ -543,2 +669,20 @@ } | ||
}, { | ||
key: 'onMouseUp', | ||
value: function onMouseUp(e) { | ||
var el = e.target; | ||
var selectionStart = el.selectionStart, | ||
selectionEnd = el.selectionEnd, | ||
value = el.value; | ||
if (selectionStart === selectionEnd) { | ||
var caretPostion = this.correctCaretPosition(value, selectionStart); | ||
if (caretPostion !== selectionStart) { | ||
this.setPatchedCaretPosition(el, caretPostion, value); | ||
} | ||
} | ||
this.props.onMouseUp(e); | ||
} | ||
}, { | ||
key: 'render', | ||
@@ -552,3 +696,4 @@ value: function render() { | ||
onChange: this.onChange, | ||
onKeyDown: this.onKeyDown | ||
onKeyDown: this.onKeyDown, | ||
onMouseUp: this.onMouseUp | ||
}); | ||
@@ -555,0 +700,0 @@ |
/*! | ||
* react-number-format - 2.0.0-alpha5 | ||
* react-number-format - 2.0.0-beta1 | ||
* Author : Sudhanshu Yadav | ||
* Copyright (c) 2016,2017 to Sudhanshu Yadav - ignitersworld.com , released under the MIT license. | ||
*/ | ||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):"object"==typeof exports?exports.NumberFormat=t(require("react")):e.NumberFormat=t(e.React)}(this,function(e){return function(e){function t(n){if(r[n])return r[n].exports;var a=r[n]={exports:{},id:n,loaded:!1};return e[n].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var r={};return t.m=e,t.c=r,t.p="",t(0)}([function(e,t,r){e.exports=r(1)},function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{default:e}}function a(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function u(){}function s(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function f(e){return e.replace(/^0+/,"")||"0"}function l(e,t){for(var r="",n=0;n<=t-1;n++)r+=e[n]||"0";return r}function p(e,t){var r={};return Object.keys(e).forEach(function(n){t[n]||(r[n]=e[n])}),r}var c=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},d=function(){function e(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,r,n){return r&&e(t.prototype,r),n&&e(t,n),t}}(),h=r(2),v=n(h),m=r(7),y=n(m),g={thousandSeparator:v.default.oneOfType([v.default.string,v.default.oneOf([!0])]),decimalSeparator:v.default.string,decimalPrecision:v.default.number,displayType:v.default.oneOf(["input","text"]),prefix:v.default.string,suffix:v.default.string,format:v.default.oneOfType([v.default.string,v.default.func]),mask:v.default.string,value:v.default.oneOfType([v.default.number,v.default.string]),customInput:v.default.func,allowNegative:v.default.bool,onKeyDown:v.default.func,onChange:v.default.func,type:v.default.oneOf(["text","tel"]),isAllowed:v.default.func},b={displayType:"input",decimalSeparator:".",allowNegative:!0,type:"text",onChange:u,onKeyDown:u,isAllowed:function(){return!0}},x=function(e){function t(e){a(this,t);var r=o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e)),n=r.optimizeValueProp(e);return r.state={value:r.formatInput(n).formattedValue},r.onChange=r.onChange.bind(r),r.onKeyDown=r.onKeyDown.bind(r),r}return i(t,e),d(t,[{key:"componentDidUpdate",value:function(e,t){this.updateValueIfRequired(e,t)}},{key:"updateValueIfRequired",value:function(e){var t=this.props,r=this.state;if(e!==t){var n=r.value,a=this.optimizeValueProp(t);void 0===a&&(a=n);var o=this.formatInput(a),i=o.formattedValue;i!==n&&this.setState({value:i})}}},{key:"getFloatValue",value:function(e){var t=this.props.decimalSeparator;return parseFloat(e.replace(t,"."))||0}},{key:"optimizeValueProp",value:function(e){var t=this.getSeparators(e),r=t.decimalSeparator,n=e.decimalPrecision,a=e.format,o=e.value;if(a||void 0===o)return o;var i="number"==typeof o;return i&&(o=o.toString()),r&&i&&(o=o.replace(".",r)),0===n?o.split(r)[0]:o}},{key:"getSeparators",value:function(e){e=e||this.props;var t=e,r=t.decimalSeparator,n=e,a=n.thousandSeparator;if(a===!0&&(a=","),r===a)throw new Error("\n Decimal separator can't be same as thousand separator.\n\n thousandSeparator: "+a+' (thousandSeparator = {true} is same as thousandSeparator = ",")\n decimalSeparator: '+r+" (default value for decimalSeparator is .)\n ");return{decimalSeparator:r,thousandSeparator:a}}},{key:"getNumberRegex",value:function(e,t){var r=this.props,n=r.format,a=r.decimalPrecision,o=this.getSeparators(),i=o.decimalSeparator;return new RegExp("\\d"+(!i||0===a||t||n?"":"|"+s(i)),e?"g":void 0)}},{key:"setCaretPosition",value:function(e,t){if(e.value=e.value,null!==e){if(e.createTextRange){var r=e.createTextRange();return r.move("character",t),r.select(),!0}return e.selectionStart||0===e.selectionStart?(e.focus(),e.setSelectionRange(t,t),!0):(e.focus(),!1)}}},{key:"setPatchedCaretPosition",value:function(e,t,r){var n=this;this.setCaretPosition(e,t),setTimeout(function(){e.value===r&&n.setCaretPosition(e,t)},0)}},{key:"formatWithPattern",value:function(e){var t=this.props,r=t.format,n=t.mask;if(!r)return e;for(var a=r.split("#").length-1,o=0,i=r,u=0,s=e.length;u<s;u++)u<a&&(o=i.indexOf("#"),i=i.replace("#",e[u]));var f=i.lastIndexOf("#");return n?i.replace(/#/g,n):i.substring(0,o+1)+(f!==-1?i.substring(f+1,i.length):"")}},{key:"formatInput",value:function(e){var t=this.props,r=t.prefix,n=t.suffix,a=(t.mask,t.format),o=t.allowNegative,i=t.decimalPrecision,u=this.getSeparators(),s=u.thousandSeparator,p=u.decimalSeparator,c=this.getNumberRegex(!0),d=void 0,h=void 0;"number"==typeof e&&(e+="");var v=new RegExp("(-)"),m=new RegExp("(-)(.)*(-)");o&&!a&&(d=v.test(e),h=m.test(e));var y=e&&e.match(c);if(!y&&h)return{value:"",formattedValue:""};if(!y&&d)return{value:"",formattedValue:"-"};if(!y)return{value:"",formattedValue:""};var g=e.match(c).join(""),b=g;if(a)"string"==typeof a?b=this.formatWithPattern(b):"function"==typeof a&&(b=a(b));else{var x=b.indexOf(p)!==-1||i,P=b.split(p),S=P[0],w=P[1]||"";S=f(S),void 0!==i&&(w=l(w,i)),s&&(S=S.replace(/(\d)(?=(\d{3})+(?!\d))/g,"$1"+s)),r&&(S=r+S),n&&(w+=n),d&&!h&&(S="-"+S),b=S+(x&&p||"")+w}return{value:(d&&!h?"-":"")+b.match(c).join(""),formattedValue:b}}},{key:"getCursorPosition",value:function(e,t,r){var n=this.getNumberRegex(),a=void 0,o=void 0;for(a=0,o=0;o<r;o++)if((e[o].match(n)||e[o]===t[a])&&("0"!==e[o]||!(t[a]||"").match(n)||"0"===t[a])){for(;e[o]!==t[a]&&a<t.length;)a++;a++}return a}},{key:"onChange",value:function(e){e.persist();var t=e.target,r=t.value,n=this.state,a=this.props,o=a.isAllowed,i=n.value,u=this.formatInput(r),s=u.formattedValue,f=u.value,l=Math.max(t.selectionStart,t.selectionEnd),p=this.getCursorPosition(r,s,l);return o(s,f,this.getFloatValue(f))||(s=i),t.value=s,this.setPatchedCaretPosition(t,p,s),s!==i&&this.setState({value:s},function(){a.onChange(e,f)}),f}},{key:"onKeyDown",value:function(e){var t=e.target,r=t.selectionStart,n=t.selectionEnd,a=t.value,o=this.props.decimalPrecision,i=e.key,u=this.getNumberRegex(!1,void 0!==o),s=new RegExp("-");if(n-r===0)if("Delete"!==i||u.test(a[r])||s.test(a[r])){if("Backspace"===i&&!u.test(a[r-1])&&!s.test(a[r-1])){e.preventDefault();for(var f=r;!u.test(a[f-1])&&f>0;)f--;this.setPatchedCaretPosition(t,f,a)}}else{e.preventDefault();for(var l=r;!u.test(a[l])&&l<a.length;)l++;this.setPatchedCaretPosition(t,l,a)}this.props.onKeyDown(e)}},{key:"render",value:function(){var e=p(this.props,g),t=c({},e,{type:this.props.type,value:this.state.value,onChange:this.onChange,onKeyDown:this.onKeyDown});if("text"===this.props.displayType)return y.default.createElement("span",e,this.state.value);if(this.props.customInput){var r=this.props.customInput;return y.default.createElement(r,t)}return y.default.createElement("input",t)}}]),t}(y.default.Component);x.propTypes=g,x.defaultProps=b,e.exports=x},function(e,t,r){e.exports=r(3)()},function(e,t,r){"use strict";var n=r(4),a=r(5),o=r(6);e.exports=function(){function e(e,t,r,n,i,u){u!==o&&a(!1,"Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types")}function t(){return e}e.isRequired=e;var r={array:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t};return r.checkPropTypes=n,r.PropTypes=r,r}},function(e,t){"use strict";function r(e){return function(){return e}}var n=function(){};n.thatReturns=r,n.thatReturnsFalse=r(!1),n.thatReturnsTrue=r(!0),n.thatReturnsNull=r(null),n.thatReturnsThis=function(){return this},n.thatReturnsArgument=function(e){return e},e.exports=n},function(e,t,r){"use strict";function n(e,t,r,n,o,i,u,s){if(a(t),!e){var f;if(void 0===t)f=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var l=[r,n,o,i,u,s],p=0;f=new Error(t.replace(/%s/g,function(){return l[p++]})),f.name="Invariant Violation"}throw f.framesToPop=1,f}}var a=function(e){};e.exports=n},function(e,t){"use strict";var r="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED";e.exports=r},function(t,r){t.exports=e}])}); | ||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):"object"==typeof exports?exports.NumberFormat=t(require("react")):e.NumberFormat=t(e.React)}(this,function(e){return function(e){function t(n){if(r[n])return r[n].exports;var o=r[n]={exports:{},id:n,loaded:!1};return e[n].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var r={};return t.m=e,t.c=r,t.p="",t(0)}([function(e,t,r){e.exports=r(1)},function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{default:e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function a(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function u(){}function s(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function f(e){return e.replace(/^0+/,"")||"0"}function l(e,t){for(var r="",n=0;n<=t-1;n++)r+=e[n]||"0";return r}function p(e,t){var r=e.split("."),n=parseFloat("0."+(r[1]||"0")).toFixed(t).split("."),o=r[0].split("").reverse().reduce(function(e,t,r){return e.length>r?(Number(e[0])+Number(t)).toString()+e.substring(1,e.length):t+e},n[0]),a=n[1];return o+(a?"."+a:"")}function c(e,t){var r={};return Object.keys(e).forEach(function(n){t[n]||(r[n]=e[n])}),r}var h=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},d=function(){function e(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,r,n){return r&&e(t.prototype,r),n&&e(t,n),t}}(),v=r(2),m=n(v),g=r(7),y=n(g),x={thousandSeparator:m.default.oneOfType([m.default.string,m.default.oneOf([!0])]),decimalSeparator:m.default.string,decimalPrecision:m.default.number,displayType:m.default.oneOf(["input","text"]),prefix:m.default.string,suffix:m.default.string,format:m.default.oneOfType([m.default.string,m.default.func]),mask:m.default.string,value:m.default.oneOfType([m.default.number,m.default.string]),customInput:m.default.func,allowNegative:m.default.bool,onKeyDown:m.default.func,onMouseUp:m.default.func,onChange:m.default.func,type:m.default.oneOf(["text","tel"]),isAllowed:m.default.func},b={displayType:"input",decimalSeparator:".",prefix:"",suffix:"",allowNegative:!0,type:"text",onChange:u,onKeyDown:u,onMouseUp:u,isAllowed:function(){return!0}},S=function(e){function t(e){o(this,t);var r=a(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e)),n=r.optimizeValueProp(e);return r.state={value:r.formatInput(n).formattedValue},r.onChange=r.onChange.bind(r),r.onKeyDown=r.onKeyDown.bind(r),r.onMouseUp=r.onMouseUp.bind(r),r}return i(t,e),d(t,[{key:"componentDidUpdate",value:function(e,t){this.updateValueIfRequired(e,t)}},{key:"updateValueIfRequired",value:function(e){var t=this.props,r=this.state;if(e!==t){var n=r.value,o=this.optimizeValueProp(t);void 0===o&&(o=n);var a=this.formatInput(o),i=a.formattedValue;i!==n&&this.setState({value:i})}}},{key:"getFloatString",value:function(e,t){t=t||this.props;var r=this.getSeparators(t),n=r.decimalSeparator,o=r.thousandSeparator;return e.replace(new RegExp(s(o||""),"g"),"").replace(n,".")}},{key:"getFloatValue",value:function(e,t){return t=t||this.props,parseFloat(this.getFloatString(e,t))||0}},{key:"optimizeValueProp",value:function(e){var t=this.getSeparators(e),r=t.decimalSeparator,n=e.decimalPrecision,o=e.format,a=e.value;if(o||void 0===a)return a;var i="number"==typeof a;if(i&&(a=a.toString()),a=this.removePrefixAndSuffix(i?a:this.getFloatString(a,e),e),"number"==typeof n&&(a=p(a,n)),r&&(a=a.replace(".",r)),a.split(r).length>2)throw new Error("\n Wrong input for value props.\n\n More than one decimalSeparator found\n ");return 0===n?a.split(r)[0]:a}},{key:"removePrefixAndSuffix",value:function(e,t){var r=t.format,n=t.prefix,o=t.suffix;if(!r&&e){var a="-"===e[0];a&&(e=e.substring(1,e.length)),e=n&&0===e.indexOf(n)?e.substring(n.length,e.length):e;var i=e.lastIndexOf(o);e=o&&i!==-1&&i===e.length-o.length?e.substring(0,i):e,a&&(e="-"+e)}return e}},{key:"getSeparators",value:function(e){e=e||this.props;var t=e,r=t.decimalSeparator,n=e,o=n.thousandSeparator;if(o===!0&&(o=","),r===o)throw new Error("\n Decimal separator can't be same as thousand separator.\n\n thousandSeparator: "+o+' (thousandSeparator = {true} is same as thousandSeparator = ",")\n decimalSeparator: '+r+" (default value for decimalSeparator is .)\n ");return{decimalSeparator:r,thousandSeparator:o}}},{key:"getNumberRegex",value:function(e,t){var r=this.props,n=r.format,o=r.decimalPrecision,a=this.getSeparators(),i=a.decimalSeparator;return new RegExp("\\d"+(!i||0===o||t||n?"":"|"+s(i)),e?"g":void 0)}},{key:"setCaretPosition",value:function(e,t){if(e.value=e.value,null!==e){if(e.createTextRange){var r=e.createTextRange();return r.move("character",t),r.select(),!0}return e.selectionStart||0===e.selectionStart?(e.focus(),e.setSelectionRange(t,t),!0):(e.focus(),!1)}}},{key:"setPatchedCaretPosition",value:function(e,t,r){var n=this;this.setCaretPosition(e,t),setTimeout(function(){e.value===r&&n.setCaretPosition(e,t)},0)}},{key:"correctCaretPosition",value:function(e,t){var r=this.props,n=r.prefix,o=r.suffix;return Math.min(Math.max(t,n.length),e.length-o.length)}},{key:"formatWithPattern",value:function(e){var t=this.props,r=t.format,n=t.mask;if(!r)return e;for(var o=r.split("#").length-1,a=0,i=r,u=0,s=e.length;u<s;u++)u<o&&(a=i.indexOf("#"),i=i.replace("#",e[u]));var f=i.lastIndexOf("#");return n?i.replace(/#/g,n):i.substring(0,a+1)+(f!==-1?i.substring(f+1,i.length):"")}},{key:"formatInput",value:function(e){var t=this.props,r=this.removePrefixAndSuffix,n=t.prefix,o=t.suffix,a=(t.mask,t.format),i=t.allowNegative,u=t.decimalPrecision,s=this.getSeparators(),p=s.thousandSeparator,c=s.decimalSeparator,h=this.getNumberRegex(!0),d=void 0,v=void 0;"number"==typeof e&&(e+="");var m=new RegExp("(-)"),g=new RegExp("(-)(.)*(-)");i&&!a&&(d=m.test(e),v=g.test(e)),e=r(e,t);var y=e&&e.match(h);if(!y&&v)return{value:"",formattedValue:""};if(!y&&d)return{value:"",formattedValue:"-"};if(!y)return{value:"",formattedValue:""};var x=e.match(h).join(""),b=x;if(a)"string"==typeof a?b=this.formatWithPattern(b):"function"==typeof a&&(b=a(b));else{var S=b.indexOf(c)!==-1||u,P=b.split(c),w=P[0],O=P[1]||"";w=f(w),void 0!==u&&(O=l(O,u)),p&&(w=w.replace(/(\d)(?=(\d{3})+(?!\d))/g,"$1"+p)),n&&(w=n+w),o&&(O+=o),d&&!v&&(w="-"+w),b=w+(S&&c||"")+O}return{value:(d&&!v?"-":"")+r(b,t).match(h).join(""),formattedValue:b}}},{key:"getCaretPosition",value:function(e,t,r){var n=this.getNumberRegex(!0),o=(e.match(n)||[]).join(""),a=(t.match(n)||[]).join(""),i=void 0,u=void 0;for(i=0,u=0;u<r;u++){var s=e[u],f=t[i]||"";if((s.match(n)||s===f)&&("0"!==s||!f.match(n)||"0"===f||o.length===a.length)){for(;s!==t[i]&&!(t[i]||"").match(n)&&i<t.length;)i++;i++}}return i=this.correctCaretPosition(t,i)}},{key:"onChange",value:function(e){e.persist();var t=e.target,r=t.value,n=this.state,o=this.props,a=o.isAllowed,i=n.value,u=this.formatInput(r),s=u.formattedValue,f=u.value,l=Math.max(t.selectionStart,t.selectionEnd),p={formattedValue:s,value:f,floatValue:this.getFloatValue(f)};a(p)||(s=i),t.value=s;var c=this.getCaretPosition(r,s,l);return this.setPatchedCaretPosition(t,c,s),s!==i&&this.setState({value:s},function(){o.onChange(e,p)}),f}},{key:"onKeyDown",value:function(e){var t=e.target,r=t.selectionEnd,n=t.value,o=t.selectionStart,a=this.props,i=a.decimalPrecision,u=a.prefix,s=a.suffix,f=e.key,l=this.getNumberRegex(!1,void 0!==i),p=new RegExp("-");if(o===r){var c=o;if("ArrowLeft"===f||"ArrowRight"===f)o+="ArrowLeft"===f?-1:1,c=this.correctCaretPosition(n,o);else if("Delete"!==f||l.test(n[o])||p.test(n[o])){if("Backspace"===f&&!l.test(n[o-1])&&!p.test(n[o-1]))for(;!l.test(n[c-1])&&c>u.length;)c--}else for(;!l.test(n[c])&&c<n.length-s.length;)c++;c!==o&&(e.preventDefault(),this.setPatchedCaretPosition(t,c,n))}this.props.onKeyDown(e)}},{key:"onMouseUp",value:function(e){var t=e.target,r=t.selectionStart,n=t.selectionEnd,o=t.value;if(r===n){var a=this.correctCaretPosition(o,r);a!==r&&this.setPatchedCaretPosition(t,a,o)}this.props.onMouseUp(e)}},{key:"render",value:function(){var e=c(this.props,x),t=h({},e,{type:this.props.type,value:this.state.value,onChange:this.onChange,onKeyDown:this.onKeyDown,onMouseUp:this.onMouseUp});if("text"===this.props.displayType)return y.default.createElement("span",e,this.state.value);if(this.props.customInput){var r=this.props.customInput;return y.default.createElement(r,t)}return y.default.createElement("input",t)}}]),t}(y.default.Component);S.propTypes=x,S.defaultProps=b,e.exports=S},function(e,t,r){e.exports=r(3)()},function(e,t,r){"use strict";var n=r(4),o=r(5),a=r(6);e.exports=function(){function e(e,t,r,n,i,u){u!==a&&o(!1,"Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types")}function t(){return e}e.isRequired=e;var r={array:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t};return r.checkPropTypes=n,r.PropTypes=r,r}},function(e,t){"use strict";function r(e){return function(){return e}}var n=function(){};n.thatReturns=r,n.thatReturnsFalse=r(!1),n.thatReturnsTrue=r(!0),n.thatReturnsNull=r(null),n.thatReturnsThis=function(){return this},n.thatReturnsArgument=function(e){return e},e.exports=n},function(e,t,r){"use strict";function n(e,t,r,n,a,i,u,s){if(o(t),!e){var f;if(void 0===t)f=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var l=[r,n,a,i,u,s],p=0;f=new Error(t.replace(/%s/g,function(){return l[p++]})),f.name="Invariant Violation"}throw f.framesToPop=1,f}}var o=function(e){};e.exports=n},function(e,t){"use strict";var r="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED";e.exports=r},function(t,r){t.exports=e}])}); |
@@ -6,24 +6,12 @@ import React from 'react'; | ||
import TextField from 'material-ui/TextField'; | ||
import {cardExpiry} from '../../custom_formatters/card_expiry'; | ||
class App extends React.Component { | ||
constructor() { | ||
super(); | ||
this.state = {}; | ||
this.formatExpiryChange = this.formatExpiryChange.bind(this); | ||
this.state = {test: 1232323.780023}; | ||
} | ||
formatExpiryChange(val) { | ||
if(val && val.length > 1 && Number(val[0]) < 1 && Number(val[1]) < 1){ | ||
val = '01'+val.substring(2,val.length); | ||
} | ||
if(val && Number(val[0]) > 1){ | ||
val = '0'+val; | ||
} | ||
if(val && val.length >1 && Number(val[0]+val[1]) > 12){ | ||
val = '12'+val.substring(2,val.length); | ||
} | ||
val = val.substring(0,2)+ (val.length > 2 ? '/'+val.substring(2,4) : ''); | ||
return val; | ||
} | ||
render() { | ||
@@ -36,3 +24,3 @@ return ( | ||
</h3> | ||
<NumberFormat value={2456981} displayType={'text'} thousandSeparator={true} prefix={'$'} /> | ||
<NumberFormat value={2456981} displayType={'text'} thousandSeparator={true} prefix={'$'}/> | ||
</div> | ||
@@ -51,3 +39,3 @@ | ||
</h3> | ||
<NumberFormat thousandSeparator={true} value={this.state.test} prefix={'$'} onChange={(e, val) => this.setState({test: val})} /> | ||
<NumberFormat thousandSeparator={'.'} decimalSeparator="," isAllowed={(values) => { return values.floatValue > 5}} value={this.state.test} prefix={'$'} decimalPrecision={3} onChange={(e, val) => this.setState({test: e.target.value})}/> | ||
</div> | ||
@@ -119,3 +107,3 @@ | ||
</h3> | ||
<NumberFormat format={this.formatExpiryChange}/> | ||
<NumberFormat format={cardExpiry}/> | ||
</div> | ||
@@ -122,0 +110,0 @@ |
@@ -9,7 +9,7 @@ var webpack = require('webpack'); | ||
files: [ | ||
'./test/input_test.js' | ||
'./test/**/*.spec.js' | ||
], | ||
reporters: ['kjhtml'], | ||
preprocessors: { | ||
'./test/*.js': [ 'webpack','sourcemap'] //preprocess with webpack | ||
'./test/**/*.js': [ 'webpack','sourcemap'] //preprocess with webpack | ||
}, | ||
@@ -16,0 +16,0 @@ webpack: { |
@@ -32,2 +32,4 @@ 'use strict'; | ||
* 10. isAllowed props to validate input and block if returns false | ||
* 11. Round to precision for passed value | ||
* 12. It should always move cursor to type area ignoring prefix and suffix | ||
*/ | ||
@@ -47,2 +49,6 @@ | ||
/** | ||
* limit decimal numbers to given precision | ||
* Not used .fixedTo because that will break with big numbers | ||
*/ | ||
function limitToPrecision(numStr, precision) { | ||
@@ -56,2 +62,21 @@ var str = ''; | ||
/** | ||
* This method is required to round prop value to given precision. | ||
* Not used .round or .fixedTo because that will break with big numbers | ||
*/ | ||
function roundToPrecision(numStr, precision) { | ||
var numberParts = numStr.split('.'); | ||
var roundedDecimalParts = parseFloat('0.' + (numberParts[1] || '0')).toFixed(precision).split('.'); | ||
var intPart = numberParts[0].split('').reverse().reduce(function (roundedStr, current, idx) { | ||
if (roundedStr.length > idx) { | ||
return (Number(roundedStr[0]) + Number(current)).toString() + roundedStr.substring(1, roundedStr.length); | ||
} | ||
return current + roundedStr; | ||
}, roundedDecimalParts[0]); | ||
var decimalPart = roundedDecimalParts[1]; | ||
return intPart + (decimalPart ? '.' + decimalPart : ''); | ||
} | ||
function omit(obj, keyMaps) { | ||
@@ -78,2 +103,3 @@ var filteredObj = {}; | ||
onKeyDown: _propTypes2.default.func, | ||
onMouseUp: _propTypes2.default.func, | ||
onChange: _propTypes2.default.func, | ||
@@ -87,2 +113,4 @@ type: _propTypes2.default.oneOf(['text', 'tel']), | ||
decimalSeparator: '.', | ||
prefix: '', | ||
suffix: '', | ||
allowNegative: true, | ||
@@ -92,2 +120,3 @@ type: 'text', | ||
onKeyDown: noop, | ||
onMouseUp: noop, | ||
isAllowed: function isAllowed() { | ||
@@ -112,2 +141,3 @@ return true; | ||
_this.onKeyDown = _this.onKeyDown.bind(_this); | ||
_this.onMouseUp = _this.onMouseUp.bind(_this); | ||
return _this; | ||
@@ -145,13 +175,23 @@ } | ||
}, { | ||
key: 'getFloatValue', | ||
value: function getFloatValue(num) { | ||
var decimalSeparator = this.props.decimalSeparator; | ||
key: 'getFloatString', | ||
value: function getFloatString(num, props) { | ||
props = props || this.props; | ||
return parseFloat(num.replace(decimalSeparator, '.')) || 0; | ||
var _getSeparators = this.getSeparators(props), | ||
decimalSeparator = _getSeparators.decimalSeparator, | ||
thousandSeparator = _getSeparators.thousandSeparator; | ||
return num.replace(new RegExp(escapeRegExp(thousandSeparator || ''), 'g'), '').replace(decimalSeparator, '.'); | ||
} | ||
}, { | ||
key: 'getFloatValue', | ||
value: function getFloatValue(num, props) { | ||
props = props || this.props; | ||
return parseFloat(this.getFloatString(num, props)) || 0; | ||
} | ||
}, { | ||
key: 'optimizeValueProp', | ||
value: function optimizeValueProp(props) { | ||
var _getSeparators = this.getSeparators(props), | ||
decimalSeparator = _getSeparators.decimalSeparator; | ||
var _getSeparators2 = this.getSeparators(props), | ||
decimalSeparator = _getSeparators2.decimalSeparator; | ||
@@ -169,7 +209,17 @@ var decimalPrecision = props.decimalPrecision, | ||
value = this.removePrefixAndSuffix(isNumber ? value : this.getFloatString(value, props), props); | ||
//round off value | ||
if (typeof decimalPrecision === 'number') value = roundToPrecision(value, decimalPrecision); | ||
//correct decimal separator | ||
if (decimalSeparator && isNumber) { | ||
if (decimalSeparator) { | ||
value = value.replace('.', decimalSeparator); | ||
} | ||
//throw error if value has two decimal seperators | ||
if (value.split(decimalSeparator).length > 2) { | ||
throw new Error('\n Wrong input for value props.\n\n More than one decimalSeparator found\n '); | ||
} | ||
//if decimalPrecision is 0 remove decimalNumbers | ||
@@ -181,2 +231,30 @@ if (decimalPrecision === 0) return value.split(decimalSeparator)[0]; | ||
}, { | ||
key: 'removePrefixAndSuffix', | ||
value: function removePrefixAndSuffix(val, props) { | ||
var format = props.format, | ||
prefix = props.prefix, | ||
suffix = props.suffix; | ||
//remove prefix and suffix | ||
if (!format && val) { | ||
var isNegative = val[0] === '-'; | ||
//remove negation sign | ||
if (isNegative) val = val.substring(1, val.length); | ||
//remove prefix | ||
val = prefix && val.indexOf(prefix) === 0 ? val.substring(prefix.length, val.length) : val; | ||
//remove suffix | ||
var suffixLastIndex = val.lastIndexOf(suffix); | ||
val = suffix && suffixLastIndex !== -1 && suffixLastIndex === val.length - suffix.length ? val.substring(0, suffixLastIndex) : val; | ||
//add negation sign back | ||
if (isNegative) val = '-' + val; | ||
} | ||
return val; | ||
} | ||
}, { | ||
key: 'getSeparators', | ||
@@ -212,4 +290,4 @@ value: function getSeparators(props) { | ||
var _getSeparators2 = this.getSeparators(), | ||
decimalSeparator = _getSeparators2.decimalSeparator; | ||
var _getSeparators3 = this.getSeparators(), | ||
decimalSeparator = _getSeparators3.decimalSeparator; | ||
@@ -259,8 +337,20 @@ return new RegExp('\\d' + (decimalSeparator && decimalPrecision !== 0 && !ignoreDecimalSeparator && !format ? '|' + escapeRegExp(decimalSeparator) : ''), g ? 'g' : undefined); | ||
} | ||
/* This keeps the caret within typing area so people can't type in between prefix or suffix */ | ||
}, { | ||
key: 'correctCaretPosition', | ||
value: function correctCaretPosition(value, caretPos) { | ||
var _props4 = this.props, | ||
prefix = _props4.prefix, | ||
suffix = _props4.suffix; | ||
return Math.min(Math.max(caretPos, prefix.length), value.length - suffix.length); | ||
} | ||
}, { | ||
key: 'formatWithPattern', | ||
value: function formatWithPattern(str) { | ||
var _props4 = this.props, | ||
format = _props4.format, | ||
mask = _props4.mask; | ||
var _props5 = this.props, | ||
format = _props5.format, | ||
mask = _props5.mask; | ||
@@ -289,13 +379,14 @@ if (!format) return str; | ||
value: function formatInput(val) { | ||
var _props5 = this.props, | ||
prefix = _props5.prefix, | ||
suffix = _props5.suffix, | ||
mask = _props5.mask, | ||
format = _props5.format, | ||
allowNegative = _props5.allowNegative, | ||
decimalPrecision = _props5.decimalPrecision; | ||
var props = this.props, | ||
removePrefixAndSuffix = this.removePrefixAndSuffix; | ||
var prefix = props.prefix, | ||
suffix = props.suffix, | ||
mask = props.mask, | ||
format = props.format, | ||
allowNegative = props.allowNegative, | ||
decimalPrecision = props.decimalPrecision; | ||
var _getSeparators3 = this.getSeparators(), | ||
thousandSeparator = _getSeparators3.thousandSeparator, | ||
decimalSeparator = _getSeparators3.decimalSeparator; | ||
var _getSeparators4 = this.getSeparators(), | ||
thousandSeparator = _getSeparators4.thousandSeparator, | ||
decimalSeparator = _getSeparators4.decimalSeparator; | ||
@@ -313,2 +404,3 @@ var maskPattern = format && typeof format == 'string' && !!mask; | ||
//check if it has negative numbers | ||
if (allowNegative && !format) { | ||
@@ -321,2 +413,5 @@ // Check number has '-' value | ||
//remove prefix and suffix | ||
val = removePrefixAndSuffix(val, props); | ||
var valMatch = val && val.match(numRegex); | ||
@@ -369,3 +464,3 @@ | ||
return { | ||
value: (hasNegative && !removeNegative ? '-' : '') + formattedValue.match(numRegex).join(''), | ||
value: (hasNegative && !removeNegative ? '-' : '') + removePrefixAndSuffix(formattedValue, props).match(numRegex).join(''), | ||
formattedValue: formattedValue | ||
@@ -375,5 +470,7 @@ }; | ||
}, { | ||
key: 'getCursorPosition', | ||
value: function getCursorPosition(inputValue, formattedValue, cursorPos) { | ||
var numRegex = this.getNumberRegex(); | ||
key: 'getCaretPosition', | ||
value: function getCaretPosition(inputValue, formattedValue, caretPos) { | ||
var numRegex = this.getNumberRegex(true); | ||
var inputNumber = (inputValue.match(numRegex) || []).join(''); | ||
var formattedNumber = (formattedValue.match(numRegex) || []).join(''); | ||
var j = void 0, | ||
@@ -384,6 +481,15 @@ i = void 0; | ||
for (i = 0; i < cursorPos; i++) { | ||
if (!inputValue[i].match(numRegex) && inputValue[i] !== formattedValue[j]) continue; | ||
if (inputValue[i] === '0' && (formattedValue[j] || '').match(numRegex) && formattedValue[j] !== '0') continue; | ||
while (inputValue[i] !== formattedValue[j] && j < formattedValue.length) { | ||
for (i = 0; i < caretPos; i++) { | ||
var currentInputChar = inputValue[i]; | ||
var currentFormatChar = formattedValue[j] || ''; | ||
//no need to increase new cursor position if formatted value does not have those characters | ||
//case inputValue = 1a23 and formattedValue = 123 | ||
if (!currentInputChar.match(numRegex) && currentInputChar !== currentFormatChar) continue; | ||
//When we are striping out leading zeros maintain the new cursor position | ||
//Case inputValue = 00023 and formattedValue = 23; | ||
if (currentInputChar === '0' && currentFormatChar.match(numRegex) && currentFormatChar !== '0' && inputNumber.length !== formattedNumber.length) continue; | ||
//we are not using currentFormatChar because j can change here | ||
while (currentInputChar !== formattedValue[j] && !(formattedValue[j] || '').match(numRegex) && j < formattedValue.length) { | ||
j++; | ||
@@ -393,2 +499,5 @@ }j++; | ||
//correct caret position if its outsize of editable area | ||
j = this.correctCaretPosition(formattedValue, j); | ||
return j; | ||
@@ -412,10 +521,14 @@ } | ||
/*Max of selectionStart and selectionEnd is taken for the patch of pixel and other mobile device cursor bug*/ | ||
/*Max of selectionStart and selectionEnd is taken for the patch of pixel and other mobile device caret bug*/ | ||
var currentCursorPosition = Math.max(el.selectionStart, el.selectionEnd); | ||
var currentCaretPosition = Math.max(el.selectionStart, el.selectionEnd); | ||
var cursorPos = this.getCursorPosition(inputValue, formattedValue, currentCursorPosition); | ||
var valueObj = { | ||
formattedValue: formattedValue, | ||
value: value, | ||
floatValue: this.getFloatValue(value) | ||
}; | ||
if (!isAllowed(formattedValue, value, this.getFloatValue(value))) { | ||
if (!isAllowed(valueObj)) { | ||
formattedValue = lastValue; | ||
@@ -427,4 +540,7 @@ } | ||
//get the caret position | ||
var caretPos = this.getCaretPosition(inputValue, formattedValue, currentCaretPosition); | ||
//set caret position | ||
this.setPatchedCaretPosition(el, cursorPos, formattedValue); | ||
this.setPatchedCaretPosition(el, caretPos, formattedValue); | ||
@@ -434,3 +550,3 @@ //change the state | ||
this.setState({ value: formattedValue }, function () { | ||
props.onChange(e, value); | ||
props.onChange(e, valueObj); | ||
}); | ||
@@ -445,6 +561,9 @@ } | ||
var el = e.target; | ||
var selectionStart = el.selectionStart, | ||
selectionEnd = el.selectionEnd, | ||
var selectionEnd = el.selectionEnd, | ||
value = el.value; | ||
var decimalPrecision = this.props.decimalPrecision; | ||
var selectionStart = el.selectionStart; | ||
var _props6 = this.props, | ||
decimalPrecision = _props6.decimalPrecision, | ||
prefix = _props6.prefix, | ||
suffix = _props6.suffix; | ||
var key = e.key; | ||
@@ -454,16 +573,23 @@ | ||
var negativeRegex = new RegExp('-'); | ||
//Handle backspace and delete against non numerical/decimal characters | ||
if (selectionEnd - selectionStart === 0) { | ||
if (key === 'Delete' && !numRegex.test(value[selectionStart]) && !negativeRegex.test(value[selectionStart])) { | ||
e.preventDefault(); | ||
var nextCursorPosition = selectionStart; | ||
while (!numRegex.test(value[nextCursorPosition]) && nextCursorPosition < value.length) { | ||
nextCursorPosition++; | ||
}this.setPatchedCaretPosition(el, nextCursorPosition, value); | ||
if (selectionStart === selectionEnd) { | ||
var newCaretPosition = selectionStart; | ||
if (key === 'ArrowLeft' || key === 'ArrowRight') { | ||
selectionStart += key === 'ArrowLeft' ? -1 : +1; | ||
newCaretPosition = this.correctCaretPosition(value, selectionStart); | ||
} else if (key === 'Delete' && !numRegex.test(value[selectionStart]) && !negativeRegex.test(value[selectionStart])) { | ||
while (!numRegex.test(value[newCaretPosition]) && newCaretPosition < value.length - suffix.length) { | ||
newCaretPosition++; | ||
} | ||
} else if (key === 'Backspace' && !numRegex.test(value[selectionStart - 1]) && !negativeRegex.test(value[selectionStart - 1])) { | ||
while (!numRegex.test(value[newCaretPosition - 1]) && newCaretPosition > prefix.length) { | ||
newCaretPosition--; | ||
} | ||
} | ||
if (newCaretPosition !== selectionStart) { | ||
e.preventDefault(); | ||
var prevCursorPosition = selectionStart; | ||
while (!numRegex.test(value[prevCursorPosition - 1]) && prevCursorPosition > 0) { | ||
prevCursorPosition--; | ||
}this.setPatchedCaretPosition(el, prevCursorPosition, value); | ||
this.setPatchedCaretPosition(el, newCaretPosition, value); | ||
} | ||
@@ -475,2 +601,20 @@ } | ||
}, { | ||
key: 'onMouseUp', | ||
value: function onMouseUp(e) { | ||
var el = e.target; | ||
var selectionStart = el.selectionStart, | ||
selectionEnd = el.selectionEnd, | ||
value = el.value; | ||
if (selectionStart === selectionEnd) { | ||
var caretPostion = this.correctCaretPosition(value, selectionStart); | ||
if (caretPostion !== selectionStart) { | ||
this.setPatchedCaretPosition(el, caretPostion, value); | ||
} | ||
} | ||
this.props.onMouseUp(e); | ||
} | ||
}, { | ||
key: 'render', | ||
@@ -484,3 +628,4 @@ value: function render() { | ||
onChange: this.onChange, | ||
onKeyDown: this.onKeyDown | ||
onKeyDown: this.onKeyDown, | ||
onMouseUp: this.onMouseUp | ||
}); | ||
@@ -487,0 +632,0 @@ |
{ | ||
"name": "react-number-format", | ||
"description": "React component to format number in an input or as a text.", | ||
"version": "2.0.0-alpha5", | ||
"version": "2.0.0-beta1", | ||
"main": "lib/number_format.js", | ||
@@ -6,0 +6,0 @@ "author": "Sudhanshu Yadav", |
@@ -5,7 +5,7 @@ # react-number-format | ||
### Features | ||
1. Allow prefix, suffix and thousand separator. | ||
2. Allow format pattern. | ||
3. Allow masking. | ||
4. Allow custom formatting handler. | ||
5. Allow formatting a input or a simple text | ||
1. Prefix, suffix and thousand separator. | ||
2. Custom format pattern. | ||
3. Masking. | ||
4. Custom formatting handler. | ||
5. Formatting a input or a simple text. | ||
@@ -21,5 +21,5 @@ ### Install | ||
| ------------- |-------------| -----| -------- | | ||
| thousandSeparator | mixed: single character string or true/false (boolean) | false | Add thousand separators on number | | ||
| decimalSeparator | mixed: single character string or true/false (boolean)| . | Support decimal point on a number | | ||
| decimalPrecision | mixed: number or boolean | false (2 if true)| If false it does not limit decimal place, if true default precision is 2 or else limits to provided decimal place | | ||
| thousandSeparator | mixed: single character string or boolean true (true is default to ,) |none| Add thousand separators on number | | ||
| decimalSeparator | single character string| . | Support decimal point on a number | | ||
| decimalPrecision | number| none| If defined it limits to given decimal precision | | ||
| allowNegative | boolean | true | allow negative numbers (Only when format option is not provided) | | ||
@@ -30,9 +30,21 @@ | prefix | String (ex : $) | none | Add a prefix before the number | | ||
| displayType | String: text / input | input | If input it renders a input element where formatting happens as you input characters. If text it renders it as a normal text in a span formatting the given value | | ||
| type | One of ['text', 'tel'] | text | Input type attribute | ||
| format | String : Hash based ex (#### #### #### ####) <br/> Or Function| none | If format given as hash string allow number input inplace of hash. If format given as function, component calls the function with unformatted number and expects formatted number. | ||
| mask | String (ex : _) | none | If mask defined, component will show non entered placed with masked value. | ||
| customInput | Component Reference | input | This allow supporting custom inputs with number format. | ||
| onChange | (e, value) => {} | none | onChange handler accepts event object through which you can get formattedValue (e.targe.value # $2,223) and second parameter non formatted value (ie: 2223) | ||
| onChange | (e, values) => {} | none | onChange handler accepts event object and [values object](#values-object) | ||
| isAllowed | ([values](#values-object)) => true or false | none | A checker function to check if input value is valid or not | ||
**Other than this it accepts all the props which can be given to a input or span based on displayType you selected.** | ||
#### values object | ||
values object is on following format | ||
```js | ||
{ | ||
formattedValue: '$23,234,235.56', //value after applying formatting | ||
value: '23234235.56', //non formatted value as string, but it maintains the decimalSeparator provided, so if , is decimal separator then value will be 23234235,56 | ||
floatValue: 23234235.56 //floating point representation. For big numbers it can have exponential syntax | ||
} | ||
``` | ||
### Examples | ||
@@ -82,14 +94,28 @@ #### Prefix and thousand separator : Format currency as text | ||
```jsx | ||
function formatExpiryChange(val){ | ||
if(val && Number(val[0]) > 1){ | ||
val = '0'+val; | ||
function limit(val, max) { | ||
if (val.length === 1 && val[0] > max[0]) { | ||
val = '0' + val; | ||
} | ||
if (val.length === 2) { | ||
if (Number(val) === 0) { | ||
val = '01'; | ||
//this can happen when user paste number | ||
} else if (val > max) { | ||
val = max; | ||
} | ||
if(val && val.length >1 && Number(val[0]+val[1]) > 12){ | ||
val = '12'+val.substring(2,val.length); | ||
} | ||
val = val.substring(0,2)+ (val.length > 2 ? '/'+val.substring(2,4) : ''); | ||
return val; | ||
} | ||
<NumberFormat format={formatExpiryChange}/> | ||
return val; | ||
} | ||
function cardExpiry(val) { | ||
let month = limit(val.substring(0, 2), '12'); | ||
let date = limit(val.substring(2, 4), '31'); | ||
return month + (date.length ? '/' + date : ''); | ||
} | ||
<NumberFormat format={cardExpiry}/> | ||
``` | ||
@@ -96,0 +122,0 @@ ![Screencast example](https://i.imgur.com/9wwdyFF.gif) |
@@ -12,2 +12,4 @@ /** | ||
* 10. isAllowed props to validate input and block if returns false | ||
* 11. Round to precision for passed value | ||
* 12. It should always move cursor to type area ignoring prefix and suffix | ||
*/ | ||
@@ -28,2 +30,6 @@ import PropTypes from 'prop-types'; | ||
/** | ||
* limit decimal numbers to given precision | ||
* Not used .fixedTo because that will break with big numbers | ||
*/ | ||
function limitToPrecision(numStr, precision) { | ||
@@ -37,2 +43,22 @@ let str = '' | ||
/** | ||
* This method is required to round prop value to given precision. | ||
* Not used .round or .fixedTo because that will break with big numbers | ||
*/ | ||
function roundToPrecision(numStr, precision) { | ||
const numberParts = numStr.split('.'); | ||
const roundedDecimalParts = parseFloat(`0.${numberParts[1] || '0'}`).toFixed(precision).split('.'); | ||
const intPart = numberParts[0].split('').reverse().reduce((roundedStr, current, idx) => { | ||
if (roundedStr.length > idx) { | ||
return (Number(roundedStr[0]) + Number(current)).toString() + roundedStr.substring(1, roundedStr.length); | ||
} | ||
return current + roundedStr; | ||
}, roundedDecimalParts[0]) | ||
const decimalPart = roundedDecimalParts[1]; | ||
return intPart + (decimalPart ? '.' + decimalPart : ''); | ||
} | ||
function omit(obj, keyMaps) { | ||
@@ -65,2 +91,3 @@ const filteredObj = {}; | ||
onKeyDown: PropTypes.func, | ||
onMouseUp: PropTypes.func, | ||
onChange: PropTypes.func, | ||
@@ -74,2 +101,4 @@ type: PropTypes.oneOf(['text', 'tel']), | ||
decimalSeparator: '.', | ||
prefix: '', | ||
suffix: '', | ||
allowNegative: true, | ||
@@ -79,2 +108,3 @@ type: 'text', | ||
onKeyDown: noop, | ||
onMouseUp: noop, | ||
isAllowed: function() {return true;} | ||
@@ -92,2 +122,3 @@ }; | ||
this.onKeyDown = this.onKeyDown.bind(this); | ||
this.onMouseUp = this.onMouseUp.bind(this); | ||
} | ||
@@ -118,7 +149,13 @@ | ||
getFloatValue(num) { | ||
const {decimalSeparator} = this.props; | ||
return parseFloat(num.replace(decimalSeparator, '.')) || 0; | ||
getFloatString(num, props) { | ||
props = props || this.props; | ||
const {decimalSeparator, thousandSeparator} = this.getSeparators(props); | ||
return num.replace(new RegExp(escapeRegExp(thousandSeparator || ''), 'g'), '').replace(decimalSeparator, '.'); | ||
} | ||
getFloatValue(num, props) { | ||
props = props || this.props; | ||
return parseFloat(this.getFloatString(num, props)) || 0; | ||
} | ||
optimizeValueProp(props) { | ||
@@ -136,7 +173,20 @@ const {decimalSeparator} = this.getSeparators(props); | ||
value = this.removePrefixAndSuffix(isNumber ? value: this.getFloatString(value, props), props); | ||
//round off value | ||
if(typeof decimalPrecision === 'number') value = roundToPrecision(value, decimalPrecision); | ||
//correct decimal separator | ||
if (decimalSeparator && isNumber) { | ||
if (decimalSeparator) { | ||
value = value.replace('.', decimalSeparator); | ||
} | ||
//throw error if value has two decimal seperators | ||
if (value.split(decimalSeparator).length > 2) { | ||
throw new Error(` | ||
Wrong input for value props.\n | ||
More than one decimalSeparator found | ||
`); | ||
} | ||
//if decimalPrecision is 0 remove decimalNumbers | ||
@@ -148,2 +198,26 @@ if (decimalPrecision === 0) return value.split(decimalSeparator)[0] | ||
removePrefixAndSuffix(val, props) { | ||
const {format, prefix, suffix} = props; | ||
//remove prefix and suffix | ||
if (!format && val) { | ||
const isNegative = val[0] === '-'; | ||
//remove negation sign | ||
if (isNegative) val = val.substring(1, val.length); | ||
//remove prefix | ||
val = prefix && val.indexOf(prefix) === 0 ? val.substring(prefix.length, val.length) : val; | ||
//remove suffix | ||
const suffixLastIndex = val.lastIndexOf(suffix); | ||
val = suffix && suffixLastIndex !== -1 && suffixLastIndex === val.length - suffix.length ? val.substring(0, suffixLastIndex) : val; | ||
//add negation sign back | ||
if (isNegative) val = '-' + val; | ||
} | ||
return val; | ||
} | ||
getSeparators(props) { | ||
@@ -217,2 +291,8 @@ props = props || this.props; | ||
/* This keeps the caret within typing area so people can't type in between prefix or suffix */ | ||
correctCaretPosition(value, caretPos) { | ||
const {prefix, suffix} = this.props; | ||
return Math.min(Math.max(caretPos, prefix.length), (value.length - suffix.length)); | ||
} | ||
formatWithPattern(str) { | ||
@@ -241,3 +321,4 @@ const {format,mask} = this.props; | ||
formatInput(val) { | ||
const {prefix, suffix, mask, format, allowNegative, decimalPrecision} = this.props; | ||
const {props, removePrefixAndSuffix} = this; | ||
const {prefix, suffix, mask, format, allowNegative, decimalPrecision} = props; | ||
const {thousandSeparator, decimalSeparator} = this.getSeparators(); | ||
@@ -254,2 +335,3 @@ const maskPattern = format && typeof format == 'string' && !!mask; | ||
//check if it has negative numbers | ||
if (allowNegative && !format) { | ||
@@ -262,2 +344,5 @@ // Check number has '-' value | ||
//remove prefix and suffix | ||
val = removePrefixAndSuffix(val, props); | ||
const valMatch = val && val.match(numRegex); | ||
@@ -312,9 +397,10 @@ | ||
return { | ||
value : (hasNegative && !removeNegative ? '-' : '') + formattedValue.match(numRegex).join(''), | ||
value : (hasNegative && !removeNegative ? '-' : '') + removePrefixAndSuffix(formattedValue, props).match(numRegex).join(''), | ||
formattedValue : formattedValue | ||
} | ||
} | ||
getCursorPosition(inputValue, formattedValue, cursorPos) { | ||
const numRegex = this.getNumberRegex(); | ||
getCaretPosition(inputValue, formattedValue, caretPos) { | ||
const numRegex = this.getNumberRegex(true); | ||
const inputNumber = (inputValue.match(numRegex) || []).join(''); | ||
const formattedNumber = (formattedValue.match(numRegex) || []).join(''); | ||
let j, i; | ||
@@ -324,9 +410,21 @@ | ||
for(i=0; i<cursorPos; i++){ | ||
if(!inputValue[i].match(numRegex) && inputValue[i] !== formattedValue[j]) continue; | ||
if (inputValue[i] === '0' && (formattedValue[j]||'').match(numRegex) && formattedValue[j] !== '0') continue; | ||
while(inputValue[i] !== formattedValue[j] && j<formattedValue.length) j++; | ||
for(i=0; i<caretPos; i++){ | ||
const currentInputChar = inputValue[i]; | ||
const currentFormatChar = formattedValue[j]||''; | ||
//no need to increase new cursor position if formatted value does not have those characters | ||
//case inputValue = 1a23 and formattedValue = 123 | ||
if(!currentInputChar.match(numRegex) && currentInputChar !== currentFormatChar) continue; | ||
//When we are striping out leading zeros maintain the new cursor position | ||
//Case inputValue = 00023 and formattedValue = 23; | ||
if (currentInputChar === '0' && currentFormatChar.match(numRegex) && currentFormatChar !== '0' && inputNumber.length !== formattedNumber.length) continue; | ||
//we are not using currentFormatChar because j can change here | ||
while(currentInputChar !== formattedValue[j] && !(formattedValue[j]||'').match(numRegex) && j<formattedValue.length) j++; | ||
j++; | ||
} | ||
//correct caret position if its outsize of editable area | ||
j = this.correctCaretPosition(formattedValue, j); | ||
return j; | ||
@@ -344,8 +442,12 @@ } | ||
/*Max of selectionStart and selectionEnd is taken for the patch of pixel and other mobile device cursor bug*/ | ||
const currentCursorPosition = Math.max(el.selectionStart, el.selectionEnd); | ||
/*Max of selectionStart and selectionEnd is taken for the patch of pixel and other mobile device caret bug*/ | ||
const currentCaretPosition = Math.max(el.selectionStart, el.selectionEnd); | ||
const cursorPos = this.getCursorPosition(inputValue, formattedValue, currentCursorPosition); | ||
const valueObj = { | ||
formattedValue, | ||
value, | ||
floatValue: this.getFloatValue(value) | ||
}; | ||
if (!isAllowed(formattedValue, value, this.getFloatValue(value))) { | ||
if (!isAllowed(valueObj)) { | ||
formattedValue = lastValue; | ||
@@ -357,4 +459,7 @@ } | ||
//get the caret position | ||
const caretPos = this.getCaretPosition(inputValue, formattedValue, currentCaretPosition); | ||
//set caret position | ||
this.setPatchedCaretPosition(el, cursorPos, formattedValue); | ||
this.setPatchedCaretPosition(el, caretPos, formattedValue); | ||
@@ -364,3 +469,3 @@ //change the state | ||
this.setState({value : formattedValue},()=>{ | ||
props.onChange(e, value); | ||
props.onChange(e, valueObj); | ||
}); | ||
@@ -374,19 +479,25 @@ } | ||
const el = e.target; | ||
const {selectionStart, selectionEnd, value} = el; | ||
const {decimalPrecision} = this.props; | ||
const {selectionEnd, value} = el; | ||
let {selectionStart} = el; | ||
const {decimalPrecision, prefix, suffix} = this.props; | ||
const {key} = e; | ||
const numRegex = this.getNumberRegex(false, decimalPrecision !== undefined); | ||
const negativeRegex = new RegExp('-'); | ||
//Handle backspace and delete against non numerical/decimal characters | ||
if(selectionEnd - selectionStart === 0) { | ||
if (key === 'Delete' && !numRegex.test(value[selectionStart]) && !negativeRegex.test(value[selectionStart])) { | ||
e.preventDefault(); | ||
let nextCursorPosition = selectionStart; | ||
while (!numRegex.test(value[nextCursorPosition]) && nextCursorPosition < value.length) nextCursorPosition++; | ||
this.setPatchedCaretPosition(el, nextCursorPosition, value); | ||
if(selectionStart === selectionEnd) { | ||
let newCaretPosition = selectionStart; | ||
if (key === 'ArrowLeft' || key === 'ArrowRight') { | ||
selectionStart += key === 'ArrowLeft' ? -1 : +1; | ||
newCaretPosition = this.correctCaretPosition(value, selectionStart); | ||
} else if (key === 'Delete' && !numRegex.test(value[selectionStart]) && !negativeRegex.test(value[selectionStart])) { | ||
while (!numRegex.test(value[newCaretPosition]) && newCaretPosition < (value.length - suffix.length)) newCaretPosition++; | ||
} else if (key === 'Backspace' && !numRegex.test(value[selectionStart - 1]) && !negativeRegex.test(value[selectionStart-1])) { | ||
while (!numRegex.test(value[newCaretPosition - 1]) && newCaretPosition > prefix.length) newCaretPosition--; | ||
} | ||
if (newCaretPosition !== selectionStart) { | ||
e.preventDefault(); | ||
let prevCursorPosition = selectionStart; | ||
while (!numRegex.test(value[prevCursorPosition - 1]) && prevCursorPosition > 0) prevCursorPosition--; | ||
this.setPatchedCaretPosition(el, prevCursorPosition, value); | ||
this.setPatchedCaretPosition(el, newCaretPosition, value); | ||
} | ||
@@ -397,2 +508,17 @@ } | ||
} | ||
onMouseUp(e) { | ||
const el = e.target; | ||
const {selectionStart, selectionEnd, value} = el; | ||
if (selectionStart === selectionEnd) { | ||
const caretPostion = this.correctCaretPosition(value, selectionStart); | ||
if (caretPostion !== selectionStart) { | ||
this.setPatchedCaretPosition(el, caretPostion, value); | ||
} | ||
} | ||
this.props.onMouseUp(e); | ||
} | ||
render() { | ||
@@ -406,2 +532,3 @@ const props = omit(this.props, propTypes); | ||
onKeyDown:this.onKeyDown, | ||
onMouseUp: this.onMouseUp | ||
}) | ||
@@ -408,0 +535,0 @@ |
@@ -7,3 +7,3 @@ module.exports = { | ||
}, | ||
devtool: "cheap-module-eval-source-map", | ||
devtool: "eval-source-map", | ||
debug: true, | ||
@@ -10,0 +10,0 @@ output: { |
154805
23
2746
168