Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-number-format

Package Overview
Dependencies
Maintainers
1
Versions
121
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-number-format - npm Package Compare versions

Comparing version 1.2.1 to 2.0.0-alpha

255

dist/react-number-format.js
/*!
* react-number-format - 1.2.1
* react-number-format - 2.0.0-alpha
* Author : Sudhanshu Yadav

@@ -89,3 +89,14 @@ * Copyright (c) 2016,2017 to Sudhanshu Yadav - ignitersworld.com , released under the MIT license.

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } //const React = require('react');
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
* 1. Validate thousand separators and decimals throw error
* 2. Thousand separator just have value true or any other string
* 3. Decimal separator should be defined only as string
* 4. Decimal precision should be only defined as number
* 5. If user don't want floating numbers set decimalPrecision to 0
* 6. User can pass value as floating point numbers or string, if user passes string decimal separator in string should match to provided decimalSeparator
* 7. Add formattedValue, numeric value, value with string in event object and not as parameters so that getting values should look consistent
* 8. dont use parseFloat that will not able to parse 2^23
* 9. Always have decimal precision
* 10. isAllowed props to validate input and block if returns false
*/

@@ -97,6 +108,19 @@

function removeLeadingZero(numStr) {
//remove leading zeros
return numStr.replace(/^0+/, '') || '0';
}
function limitToPrecision(numStr, precision) {
var str = '';
for (var i = 0; i <= precision - 1; i++) {
str += numStr[i] || '0';
}
return str;
}
var propTypes = {
thousandSeparator: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.bool]),
decimalSeparator: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.bool]),
decimalPrecision: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.bool]),
thousandSeparator: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.oneOf([true])]),
decimalSeparator: _propTypes2.default.string,
decimalPrecision: _propTypes2.default.number,
displayType: _propTypes2.default.oneOf(['input', 'text']),

@@ -111,3 +135,4 @@ prefix: _propTypes2.default.string,

onKeyDown: _propTypes2.default.func,
onChange: _propTypes2.default.func
onChange: _propTypes2.default.func,
isAllowed: _propTypes2.default.func
};

@@ -118,4 +143,6 @@

decimalSeparator: '.',
decimalPrecision: false,
allowNegative: true
allowNegative: true,
isAllowed: function isAllowed() {
return true;
}
};

@@ -131,4 +158,5 @@

var value = _this.optimizeValueProp(props);
_this.state = {
value: _this.formatInput(props.value).formattedValue
value: _this.formatInput(value).formattedValue
};

@@ -141,16 +169,70 @@ _this.onChange = _this.onChange.bind(_this);

_createClass(NumberFormat, [{
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(newProps) {
if (newProps.value !== this.props.value) {
this.setState({
value: this.formatInput(newProps.value).formattedValue
});
key: 'componentDidUpdate',
value: function componentDidUpdate(prevProps, prevState) {
this.updateValueIfRequired(prevProps, prevState);
}
}, {
key: 'updateValueIfRequired',
value: function updateValueIfRequired(prevProps) {
var props = this.props,
state = this.state;
if (prevProps !== props) {
var stateValue = state.value;
var value = this.optimizeValueProp(props);
if (value === undefined) value = stateValue;
var _formatInput = this.formatInput(value),
formattedValue = _formatInput.formattedValue;
if (formattedValue !== stateValue) {
this.setState({
value: this.formatInput(value).formattedValue
});
}
}
}
}, {
key: 'getFloatValue',
value: function getFloatValue(num) {
var decimalSeparator = this.props.decimalSeparator;
return parseFloat(num.replace(decimalSeparator, '.')) || 0;
}
}, {
key: 'optimizeValueProp',
value: function optimizeValueProp(props) {
var _getSeparators = this.getSeparators(props),
decimalSeparator = _getSeparators.decimalSeparator;
var value = props.value,
decimalPrecision = props.decimalPrecision,
format = props.format;
if (format || value === undefined) return value;
var isNumber = typeof value === 'number';
if (isNumber) value = value.toString();
//correct decimal separator
if (decimalSeparator && isNumber) {
value = value.replace('.', decimalSeparator);
}
//if decimalPrecision is 0 remove decimalNumbers
if (decimalPrecision === 0) return value.split(decimalSeparator)[0];
return value;
}
}, {
key: 'getSeparators',
value: function getSeparators() {
var _props = this.props,
thousandSeparator = _props.thousandSeparator,
decimalSeparator = _props.decimalSeparator;
value: function getSeparators(props) {
var _ref = props || this.props,
thousandSeparator = _ref.thousandSeparator,
decimalSeparator = _ref.decimalSeparator,
decimalPrecision = _ref.decimalPrecision;

@@ -161,14 +243,6 @@ if (thousandSeparator === true) {

if (decimalSeparator && thousandSeparator && typeof decimalSeparator !== 'string') {
decimalSeparator = thousandSeparator === '.' ? ',' : '.';
if (decimalSeparator === thousandSeparator) {
throw new Error('\n Decimal separator can\'t be same as thousand separator.\n\n thousandSeparator: ' + thousandSeparator + ' (thousandSeparator = {true} is same as thousandSeparator = ",")\n decimalSeparator: ' + decimalSeparator + ' (default value for decimalSeparator is .)\n ');
}
if (thousandSeparator === '.') {
decimalSeparator = ',';
}
if (decimalSeparator === true) {
decimalSeparator = '.';
}
return {

@@ -181,9 +255,11 @@ decimalSeparator: decimalSeparator,

key: 'getNumberRegex',
value: function getNumberRegex(g, ignoreDecimalSeperator) {
var format = this.props.format;
value: function getNumberRegex(g, ignoreDecimalSeparator) {
var _props = this.props,
format = _props.format,
decimalPrecision = _props.decimalPrecision;
var _getSeparators = this.getSeparators(),
decimalSeparator = _getSeparators.decimalSeparator;
var _getSeparators2 = this.getSeparators(),
decimalSeparator = _getSeparators2.decimalSeparator;
return new RegExp('\\d' + (decimalSeparator && !ignoreDecimalSeperator && !format ? '|' + escapeRegExp(decimalSeparator) : ''), g ? 'g' : undefined);
return new RegExp('\\d' + (decimalSeparator && decimalPrecision !== 0 && !ignoreDecimalSeparator && !format ? '|' + escapeRegExp(decimalSeparator) : ''), g ? 'g' : undefined);
}

@@ -217,2 +293,17 @@ }, {

}, {
key: 'setPatchedCaretPosition',
value: function setPatchedCaretPosition(el, caretPos) {
var _this2 = this;
/*
setting caret position within timeout of 0ms is required for mobile chrome,
otherwise browser resets the caret position after we set it
We are also setting it without timeout so that in normal browser we don't see the flickering
*/
this.setCaretPosition(el, caretPos);
setTimeout(function () {
return _this2.setCaretPosition(el, caretPos);
}, 0);
}
}, {
key: 'formatWithPattern',

@@ -254,5 +345,5 @@ value: function formatWithPattern(str) {

var _getSeparators2 = this.getSeparators(),
thousandSeparator = _getSeparators2.thousandSeparator,
decimalSeparator = _getSeparators2.decimalSeparator;
var _getSeparators3 = this.getSeparators(),
thousandSeparator = _getSeparators3.thousandSeparator,
decimalSeparator = _getSeparators3.decimalSeparator;

@@ -298,27 +389,18 @@ var maskPattern = format && typeof format == 'string' && !!mask;

} else {
var beforeDecimal = formattedValue,
afterDecimal = '';
var hasDecimals = formattedValue.indexOf(decimalSeparator) !== -1 || decimalPrecision !== false;
if (decimalSeparator && hasDecimals) {
var parts = void 0;
if (decimalPrecision !== false) {
var precision = decimalPrecision === true ? 2 : decimalPrecision;
if (decimalSeparator !== '.') {
// Replace custom decimalSeparator with '.' for parseFloat function
parts = parseFloat(formattedValue.replace(decimalSeparator, '.')).toFixed(precision);
// Put custom decimalSeparator back
parts = parts.replace('.', decimalSeparator);
} else {
parts = parseFloat(formattedValue).toFixed(precision);
}
parts = parts.split(decimalSeparator);
} else {
parts = formattedValue.split(decimalSeparator);
}
beforeDecimal = parts[0];
afterDecimal = parts[1];
}
var hasDecimalSeparator = formattedValue.indexOf(decimalSeparator) !== -1 || decimalPrecision;
var parts = formattedValue.split(decimalSeparator);
var beforeDecimal = parts[0];
var afterDecimal = parts[1] || '';
//remove leading zeros from number before decimal
beforeDecimal = removeLeadingZero(beforeDecimal);
//apply decimal precision if its defined
if (decimalPrecision !== undefined) afterDecimal = limitToPrecision(afterDecimal, decimalPrecision);
if (thousandSeparator) {
beforeDecimal = beforeDecimal.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + thousandSeparator);
}
//add prefix and suffix

@@ -330,3 +412,3 @@ if (prefix) beforeDecimal = prefix + beforeDecimal;

formattedValue = beforeDecimal + (hasDecimals && decimalSeparator || '') + afterDecimal;
formattedValue = beforeDecimal + (hasDecimalSeparator && decimalSeparator || '') + afterDecimal;
}

@@ -347,4 +429,6 @@

j = 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) {

@@ -360,3 +444,3 @@ j++;

value: function onChangeHandler(e, callback) {
var _this2 = this;
var _this3 = this;

@@ -366,22 +450,26 @@ e.persist();

var inputValue = el.value;
var isAllowed = this.props.isAllowed;
var _formatInput = this.formatInput(inputValue),
formattedValue = _formatInput.formattedValue,
value = _formatInput.value;
var lastValue = this.state.value;
var cursorPos = el.selectionStart;
var _formatInput2 = this.formatInput(inputValue),
formattedValue = _formatInput2.formattedValue,
value = _formatInput2.value;
var cursorPos = this.getCursorPosition(inputValue, formattedValue, el.selectionStart);
//set caret position befor setState
//this.setPatchedCaretPosition(el, cursorPos);
if (!isAllowed(formattedValue, value, this.getFloatValue(value))) {
formattedValue = lastValue;
}
//change the state
this.setState({ value: formattedValue }, function () {
cursorPos = _this2.getCursorPosition(inputValue, formattedValue, cursorPos);
/*
setting caret position within timeout of 0ms is required for mobile chrome,
otherwise browser resets the caret position after we set it
We are also setting it without timeout so that in normal browser we don't see the flickering
*/
_this2.setCaretPosition(el, cursorPos);
setTimeout(function () {
return _this2.setCaretPosition(el, cursorPos);
}, 0);
if (callback) callback(e, value);
//reset again after setState so if formattedValue is other then
_this3.setPatchedCaretPosition(el, cursorPos);
if (callback && formattedValue !== lastValue) callback(e, value);
});

@@ -404,9 +492,15 @@

var decimalPrecision = this.props.decimalPrecision;
var key = e.key;
var key = e.key,
which = e.which,
keyCode = e.keyCode;
var numRegex = this.getNumberRegex(false, decimalPrecision !== false);
var numRegex = this.getNumberRegex(false, decimalPrecision !== undefined);
console.log(numRegex.toString(), key, which, keyCode);
console.log(e);
var negativeRegex = new RegExp('-');
//Handle backspace and delete against non numerical/decimal characters
if (selectionEnd - selectionStart === 0) {
console.log('coming here');
if (key === 'Delete' && !numRegex.test(value[selectionStart]) && !negativeRegex.test(value[selectionStart])) {
console.log('delete');
e.preventDefault();

@@ -416,4 +510,5 @@ var nextCursorPosition = selectionStart;

nextCursorPosition++;
}this.setCaretPosition(el, nextCursorPosition);
}this.setPatchedCaretPosition(el, nextCursorPosition);
} else if (key === 'Backspace' && !numRegex.test(value[selectionStart - 1]) && !negativeRegex.test(value[selectionStart - 1])) {
console.log('Backspace');
e.preventDefault();

@@ -423,3 +518,3 @@ var prevCursorPosition = selectionStart;

prevCursorPosition--;
}this.setCaretPosition(el, prevCursorPosition);
}this.setPatchedCaretPosition(el, prevCursorPosition);
}

@@ -426,0 +521,0 @@ }

/*!
* react-number-format - 1.2.1
* react-number-format - 2.0.0-alpha
* 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 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(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}var s=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},f=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}}(),l=r(2),p=n(l),c=r(7),d=n(c),h={thousandSeparator:p.default.oneOfType([p.default.string,p.default.bool]),decimalSeparator:p.default.oneOfType([p.default.string,p.default.bool]),decimalPrecision:p.default.oneOfType([p.default.number,p.default.bool]),displayType:p.default.oneOf(["input","text"]),prefix:p.default.string,suffix:p.default.string,format:p.default.oneOfType([p.default.string,p.default.func]),mask:p.default.string,value:p.default.oneOfType([p.default.number,p.default.string]),customInput:p.default.func,allowNegative:p.default.bool,onKeyDown:p.default.func,onChange:p.default.func},v={displayType:"input",decimalSeparator:".",decimalPrecision:!1,allowNegative:!0},m=function(e){function t(e){o(this,t);var r=a(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e));return r.state={value:r.formatInput(e.value).formattedValue},r.onChange=r.onChange.bind(r),r.onKeyDown=r.onKeyDown.bind(r),r}return i(t,e),f(t,[{key:"componentWillReceiveProps",value:function(e){e.value!==this.props.value&&this.setState({value:this.formatInput(e.value).formattedValue})}},{key:"getSeparators",value:function(){var e=this.props,t=e.thousandSeparator,r=e.decimalSeparator;return t===!0&&(t=","),r&&t&&"string"!=typeof r&&(r="."===t?",":"."),"."===t&&(r=","),r===!0&&(r="."),{decimalSeparator:r,thousandSeparator:t}}},{key:"getNumberRegex",value:function(e,t){var r=this.props.format,n=this.getSeparators(),o=n.decimalSeparator;return new RegExp("\\d"+(!o||t||r?"":"|"+u(o)),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:"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=t.prefix,n=t.suffix,o=(t.mask,t.format),a=t.allowNegative,i=t.decimalPrecision,u=this.getSeparators(),s=u.thousandSeparator,f=u.decimalSeparator,l=this.getNumberRegex(!0),p=void 0,c=void 0;"number"==typeof e&&(e+="");var d=new RegExp("(-)"),h=new RegExp("(-)(.)*(-)");a&&!o&&(p=d.test(e),c=h.test(e));var v=e&&e.match(l);if(!v&&c)return{value:"",formattedValue:""};if(!v&&p)return{value:"",formattedValue:"-"};if(!v)return{value:"",formattedValue:""};var m=e.match(l).join(""),y=m;if(o)"string"==typeof o?y=this.formatWithPattern(y):"function"==typeof o&&(y=o(y));else{var g=y,b="",x=y.indexOf(f)!==-1||i!==!1;if(f&&x){var O=void 0;if(i!==!1){var w=i===!0?2:i;"."!==f?(O=parseFloat(y.replace(f,".")).toFixed(w),O=O.replace(".",f)):O=parseFloat(y).toFixed(w),O=O.split(f)}else O=y.split(f);g=O[0],b=O[1]}s&&(g=g.replace(/(\d)(?=(\d{3})+(?!\d))/g,"$1"+s)),r&&(g=r+g),n&&(b+=n),p&&!c&&(g="-"+g),y=g+(x&&f||"")+b}return{value:(p&&!c?"-":"")+y.match(l).join(""),formattedValue:y}}},{key:"getCursorPosition",value:function(e,t,r){var n=this.getNumberRegex(),o=void 0,a=void 0;for(o=0,a=0;a<r;a++)if(e[a].match(n)||e[a]===t[o]){for(;e[a]!==t[o]&&o<t.length;)o++;o++}return o}},{key:"onChangeHandler",value:function(e,t){var r=this;e.persist();var n=e.target,o=n.value,a=this.formatInput(o),i=a.formattedValue,u=a.value,s=n.selectionStart;return this.setState({value:i},function(){s=r.getCursorPosition(o,i,s),r.setCaretPosition(n,s),setTimeout(function(){return r.setCaretPosition(n,s)},0),t&&t(e,u)}),u}},{key:"onChange",value:function(e){this.onChangeHandler(e,this.props.onChange)}},{key:"onKeyDown",value:function(e){var t=e.target,r=t.selectionStart,n=t.selectionEnd,o=t.value,a=this.props.decimalPrecision,i=e.key,u=this.getNumberRegex(!1,a!==!1),s=new RegExp("-");if(n-r===0)if("Delete"!==i||u.test(o[r])||s.test(o[r])){if("Backspace"===i&&!u.test(o[r-1])&&!s.test(o[r-1])){e.preventDefault();for(var f=r;!u.test(o[f-1])&&f>0;)f--;this.setCaretPosition(t,f)}}else{e.preventDefault();for(var l=r;!u.test(o[l])&&l<o.length;)l++;this.setCaretPosition(t,l)}this.props.onKeyDown&&this.props.onKeyDown(e)}},{key:"render",value:function(){var e=s({},this.props);Object.keys(h).forEach(function(t){delete e[t]});var t=s({},e,{type:"text",value:this.state.value,onChange:this.onChange,onKeyDown:this.onKeyDown});if("text"===this.props.displayType)return d.default.createElement("span",e,this.state.value);if(this.props.customInput){var r=this.props.customInput;return d.default.createElement(r,t)}return d.default.createElement("input",t)}}]),t}(d.default.Component);m.propTypes=h,m.defaultProps=v,e.exports=m},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}])});
!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(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function s(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}var f=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},c=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}}(),p=r(2),d=n(p),h=r(7),v=n(h),m={thousandSeparator:d.default.oneOfType([d.default.string,d.default.oneOf([!0])]),decimalSeparator:d.default.string,decimalPrecision:d.default.number,displayType:d.default.oneOf(["input","text"]),prefix:d.default.string,suffix:d.default.string,format:d.default.oneOfType([d.default.string,d.default.func]),mask:d.default.string,value:d.default.oneOfType([d.default.number,d.default.string]),customInput:d.default.func,allowNegative:d.default.bool,onKeyDown:d.default.func,onChange:d.default.func,isAllowed:d.default.func},g={displayType:"input",decimalSeparator:".",allowNegative:!0,isAllowed:function(){return!0}},y=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),c(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:this.formatInput(a).formattedValue})}}},{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.value,a=e.decimalPrecision,o=e.format;if(o||void 0===n)return n;var i="number"==typeof n;return i&&(n=n.toString()),r&&i&&(n=n.replace(".",r)),0===a?n.split(r)[0]:n}},{key:"getSeparators",value:function(e){var t=e||this.props,r=t.thousandSeparator,n=t.decimalSeparator;t.decimalPrecision;if(r===!0&&(r=","),n===r)throw new Error("\n Decimal separator can't be same as thousand separator.\n\n thousandSeparator: "+r+' (thousandSeparator = {true} is same as thousandSeparator = ",")\n decimalSeparator: '+n+" (default value for decimalSeparator is .)\n ");return{decimalSeparator:n,thousandSeparator:r}}},{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?"":"|"+u(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){var r=this;this.setCaretPosition(e,t),setTimeout(function(){return r.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 l=i.lastIndexOf("#");return n?i.replace(/#/g,n):i.substring(0,o+1)+(l!==-1?i.substring(l+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(),f=u.thousandSeparator,c=u.decimalSeparator,p=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 g=e&&e.match(p);if(!g&&h)return{value:"",formattedValue:""};if(!g&&d)return{value:"",formattedValue:"-"};if(!g)return{value:"",formattedValue:""};var y=e.match(p).join(""),b=y;if(a)"string"==typeof a?b=this.formatWithPattern(b):"function"==typeof a&&(b=a(b));else{var x=b.indexOf(c)!==-1||i,P=b.split(c),S=P[0],w=P[1]||"";S=s(S),void 0!==i&&(w=l(w,i)),f&&(S=S.replace(/(\d)(?=(\d{3})+(?!\d))/g,"$1"+f)),r&&(S=r+S),n&&(w+=n),d&&!h&&(S="-"+S),b=S+(x&&c||"")+w}return{value:(d&&!h?"-":"")+b.match(p).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:"onChangeHandler",value:function(e,t){var r=this;e.persist();var n=e.target,a=n.value,o=this.props.isAllowed,i=this.state.value,u=this.formatInput(a),s=u.formattedValue,l=u.value,f=this.getCursorPosition(a,s,n.selectionStart);return o(s,l,this.getFloatValue(l))||(s=i),this.setState({value:s},function(){r.setPatchedCaretPosition(n,f),t&&s!==i&&t(e,l)}),l}},{key:"onChange",value:function(e){this.onChangeHandler(e,this.props.onChange)}},{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=e.which,s=e.keyCode,l=this.getNumberRegex(!1,void 0!==o);console.log(l.toString(),i,u,s),console.log(e);var f=new RegExp("-");if(n-r===0)if(console.log("coming here"),"Delete"!==i||l.test(a[r])||f.test(a[r])){if("Backspace"===i&&!l.test(a[r-1])&&!f.test(a[r-1])){console.log("Backspace"),e.preventDefault();for(var c=r;!l.test(a[c-1])&&c>0;)c--;this.setPatchedCaretPosition(t,c)}}else{console.log("delete"),e.preventDefault();for(var p=r;!l.test(a[p])&&p<a.length;)p++;this.setPatchedCaretPosition(t,p)}this.props.onKeyDown&&this.props.onKeyDown(e)}},{key:"render",value:function(){var e=f({},this.props);Object.keys(m).forEach(function(t){delete e[t]});var t=f({},e,{type:"text",value:this.state.value,onChange:this.onChange,onKeyDown:this.onKeyDown});if("text"===this.props.displayType)return v.default.createElement("span",e,this.state.value);if(this.props.customInput){var r=this.props.customInput;return v.default.createElement(r,t)}return v.default.createElement("input",t)}}]),t}(v.default.Component);y.propTypes=m,y.defaultProps=g,e.exports=y},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 l;if(void 0===t)l=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var f=[r,n,o,i,u,s],c=0;l=new Error(t.replace(/%s/g,function(){return f[c++]})),l.name="Invariant Violation"}throw l.framesToPop=1,l}}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}])});

@@ -53,3 +53,3 @@ import React from 'react';

</h3>
<NumberFormat thousandSeparator={true} decimalPrecision={true} prefix={'$'}/>
<NumberFormat thousandSeparator={true} decimalPrecision={3} prefix={'$'}/>
</div>

@@ -56,0 +56,0 @@

@@ -21,3 +21,14 @@ 'use strict';

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } //const React = require('react');
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
* 1. Validate thousand separators and decimals throw error
* 2. Thousand separator just have value true or any other string
* 3. Decimal separator should be defined only as string
* 4. Decimal precision should be only defined as number
* 5. If user don't want floating numbers set decimalPrecision to 0
* 6. User can pass value as floating point numbers or string, if user passes string decimal separator in string should match to provided decimalSeparator
* 7. Add formattedValue, numeric value, value with string in event object and not as parameters so that getting values should look consistent
* 8. dont use parseFloat that will not able to parse 2^23
* 9. Always have decimal precision
* 10. isAllowed props to validate input and block if returns false
*/

@@ -29,6 +40,19 @@

function removeLeadingZero(numStr) {
//remove leading zeros
return numStr.replace(/^0+/, '') || '0';
}
function limitToPrecision(numStr, precision) {
var str = '';
for (var i = 0; i <= precision - 1; i++) {
str += numStr[i] || '0';
}
return str;
}
var propTypes = {
thousandSeparator: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.bool]),
decimalSeparator: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.bool]),
decimalPrecision: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.bool]),
thousandSeparator: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.oneOf([true])]),
decimalSeparator: _propTypes2.default.string,
decimalPrecision: _propTypes2.default.number,
displayType: _propTypes2.default.oneOf(['input', 'text']),

@@ -43,3 +67,4 @@ prefix: _propTypes2.default.string,

onKeyDown: _propTypes2.default.func,
onChange: _propTypes2.default.func
onChange: _propTypes2.default.func,
isAllowed: _propTypes2.default.func
};

@@ -50,4 +75,6 @@

decimalSeparator: '.',
decimalPrecision: false,
allowNegative: true
allowNegative: true,
isAllowed: function isAllowed() {
return true;
}
};

@@ -63,4 +90,5 @@

var value = _this.optimizeValueProp(props);
_this.state = {
value: _this.formatInput(props.value).formattedValue
value: _this.formatInput(value).formattedValue
};

@@ -73,16 +101,70 @@ _this.onChange = _this.onChange.bind(_this);

_createClass(NumberFormat, [{
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(newProps) {
if (newProps.value !== this.props.value) {
this.setState({
value: this.formatInput(newProps.value).formattedValue
});
key: 'componentDidUpdate',
value: function componentDidUpdate(prevProps, prevState) {
this.updateValueIfRequired(prevProps, prevState);
}
}, {
key: 'updateValueIfRequired',
value: function updateValueIfRequired(prevProps) {
var props = this.props,
state = this.state;
if (prevProps !== props) {
var stateValue = state.value;
var value = this.optimizeValueProp(props);
if (value === undefined) value = stateValue;
var _formatInput = this.formatInput(value),
formattedValue = _formatInput.formattedValue;
if (formattedValue !== stateValue) {
this.setState({
value: this.formatInput(value).formattedValue
});
}
}
}
}, {
key: 'getFloatValue',
value: function getFloatValue(num) {
var decimalSeparator = this.props.decimalSeparator;
return parseFloat(num.replace(decimalSeparator, '.')) || 0;
}
}, {
key: 'optimizeValueProp',
value: function optimizeValueProp(props) {
var _getSeparators = this.getSeparators(props),
decimalSeparator = _getSeparators.decimalSeparator;
var value = props.value,
decimalPrecision = props.decimalPrecision,
format = props.format;
if (format || value === undefined) return value;
var isNumber = typeof value === 'number';
if (isNumber) value = value.toString();
//correct decimal separator
if (decimalSeparator && isNumber) {
value = value.replace('.', decimalSeparator);
}
//if decimalPrecision is 0 remove decimalNumbers
if (decimalPrecision === 0) return value.split(decimalSeparator)[0];
return value;
}
}, {
key: 'getSeparators',
value: function getSeparators() {
var _props = this.props,
thousandSeparator = _props.thousandSeparator,
decimalSeparator = _props.decimalSeparator;
value: function getSeparators(props) {
var _ref = props || this.props,
thousandSeparator = _ref.thousandSeparator,
decimalSeparator = _ref.decimalSeparator,
decimalPrecision = _ref.decimalPrecision;

@@ -93,14 +175,6 @@ if (thousandSeparator === true) {

if (decimalSeparator && thousandSeparator && typeof decimalSeparator !== 'string') {
decimalSeparator = thousandSeparator === '.' ? ',' : '.';
if (decimalSeparator === thousandSeparator) {
throw new Error('\n Decimal separator can\'t be same as thousand separator.\n\n thousandSeparator: ' + thousandSeparator + ' (thousandSeparator = {true} is same as thousandSeparator = ",")\n decimalSeparator: ' + decimalSeparator + ' (default value for decimalSeparator is .)\n ');
}
if (thousandSeparator === '.') {
decimalSeparator = ',';
}
if (decimalSeparator === true) {
decimalSeparator = '.';
}
return {

@@ -113,9 +187,11 @@ decimalSeparator: decimalSeparator,

key: 'getNumberRegex',
value: function getNumberRegex(g, ignoreDecimalSeperator) {
var format = this.props.format;
value: function getNumberRegex(g, ignoreDecimalSeparator) {
var _props = this.props,
format = _props.format,
decimalPrecision = _props.decimalPrecision;
var _getSeparators = this.getSeparators(),
decimalSeparator = _getSeparators.decimalSeparator;
var _getSeparators2 = this.getSeparators(),
decimalSeparator = _getSeparators2.decimalSeparator;
return new RegExp('\\d' + (decimalSeparator && !ignoreDecimalSeperator && !format ? '|' + escapeRegExp(decimalSeparator) : ''), g ? 'g' : undefined);
return new RegExp('\\d' + (decimalSeparator && decimalPrecision !== 0 && !ignoreDecimalSeparator && !format ? '|' + escapeRegExp(decimalSeparator) : ''), g ? 'g' : undefined);
}

@@ -149,2 +225,17 @@ }, {

}, {
key: 'setPatchedCaretPosition',
value: function setPatchedCaretPosition(el, caretPos) {
var _this2 = this;
/*
setting caret position within timeout of 0ms is required for mobile chrome,
otherwise browser resets the caret position after we set it
We are also setting it without timeout so that in normal browser we don't see the flickering
*/
this.setCaretPosition(el, caretPos);
setTimeout(function () {
return _this2.setCaretPosition(el, caretPos);
}, 0);
}
}, {
key: 'formatWithPattern',

@@ -186,5 +277,5 @@ value: function formatWithPattern(str) {

var _getSeparators2 = this.getSeparators(),
thousandSeparator = _getSeparators2.thousandSeparator,
decimalSeparator = _getSeparators2.decimalSeparator;
var _getSeparators3 = this.getSeparators(),
thousandSeparator = _getSeparators3.thousandSeparator,
decimalSeparator = _getSeparators3.decimalSeparator;

@@ -230,27 +321,18 @@ var maskPattern = format && typeof format == 'string' && !!mask;

} else {
var beforeDecimal = formattedValue,
afterDecimal = '';
var hasDecimals = formattedValue.indexOf(decimalSeparator) !== -1 || decimalPrecision !== false;
if (decimalSeparator && hasDecimals) {
var parts = void 0;
if (decimalPrecision !== false) {
var precision = decimalPrecision === true ? 2 : decimalPrecision;
if (decimalSeparator !== '.') {
// Replace custom decimalSeparator with '.' for parseFloat function
parts = parseFloat(formattedValue.replace(decimalSeparator, '.')).toFixed(precision);
// Put custom decimalSeparator back
parts = parts.replace('.', decimalSeparator);
} else {
parts = parseFloat(formattedValue).toFixed(precision);
}
parts = parts.split(decimalSeparator);
} else {
parts = formattedValue.split(decimalSeparator);
}
beforeDecimal = parts[0];
afterDecimal = parts[1];
}
var hasDecimalSeparator = formattedValue.indexOf(decimalSeparator) !== -1 || decimalPrecision;
var parts = formattedValue.split(decimalSeparator);
var beforeDecimal = parts[0];
var afterDecimal = parts[1] || '';
//remove leading zeros from number before decimal
beforeDecimal = removeLeadingZero(beforeDecimal);
//apply decimal precision if its defined
if (decimalPrecision !== undefined) afterDecimal = limitToPrecision(afterDecimal, decimalPrecision);
if (thousandSeparator) {
beforeDecimal = beforeDecimal.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + thousandSeparator);
}
//add prefix and suffix

@@ -262,3 +344,3 @@ if (prefix) beforeDecimal = prefix + beforeDecimal;

formattedValue = beforeDecimal + (hasDecimals && decimalSeparator || '') + afterDecimal;
formattedValue = beforeDecimal + (hasDecimalSeparator && decimalSeparator || '') + afterDecimal;
}

@@ -279,4 +361,6 @@

j = 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) {

@@ -292,3 +376,3 @@ j++;

value: function onChangeHandler(e, callback) {
var _this2 = this;
var _this3 = this;

@@ -298,22 +382,26 @@ e.persist();

var inputValue = el.value;
var isAllowed = this.props.isAllowed;
var _formatInput = this.formatInput(inputValue),
formattedValue = _formatInput.formattedValue,
value = _formatInput.value;
var lastValue = this.state.value;
var cursorPos = el.selectionStart;
var _formatInput2 = this.formatInput(inputValue),
formattedValue = _formatInput2.formattedValue,
value = _formatInput2.value;
var cursorPos = this.getCursorPosition(inputValue, formattedValue, el.selectionStart);
//set caret position befor setState
//this.setPatchedCaretPosition(el, cursorPos);
if (!isAllowed(formattedValue, value, this.getFloatValue(value))) {
formattedValue = lastValue;
}
//change the state
this.setState({ value: formattedValue }, function () {
cursorPos = _this2.getCursorPosition(inputValue, formattedValue, cursorPos);
/*
setting caret position within timeout of 0ms is required for mobile chrome,
otherwise browser resets the caret position after we set it
We are also setting it without timeout so that in normal browser we don't see the flickering
*/
_this2.setCaretPosition(el, cursorPos);
setTimeout(function () {
return _this2.setCaretPosition(el, cursorPos);
}, 0);
if (callback) callback(e, value);
//reset again after setState so if formattedValue is other then
_this3.setPatchedCaretPosition(el, cursorPos);
if (callback && formattedValue !== lastValue) callback(e, value);
});

@@ -336,9 +424,15 @@

var decimalPrecision = this.props.decimalPrecision;
var key = e.key;
var key = e.key,
which = e.which,
keyCode = e.keyCode;
var numRegex = this.getNumberRegex(false, decimalPrecision !== false);
var numRegex = this.getNumberRegex(false, decimalPrecision !== undefined);
console.log(numRegex.toString(), key, which, keyCode);
console.log(e);
var negativeRegex = new RegExp('-');
//Handle backspace and delete against non numerical/decimal characters
if (selectionEnd - selectionStart === 0) {
console.log('coming here');
if (key === 'Delete' && !numRegex.test(value[selectionStart]) && !negativeRegex.test(value[selectionStart])) {
console.log('delete');
e.preventDefault();

@@ -348,4 +442,5 @@ var nextCursorPosition = selectionStart;

nextCursorPosition++;
}this.setCaretPosition(el, nextCursorPosition);
}this.setPatchedCaretPosition(el, nextCursorPosition);
} else if (key === 'Backspace' && !numRegex.test(value[selectionStart - 1]) && !negativeRegex.test(value[selectionStart - 1])) {
console.log('Backspace');
e.preventDefault();

@@ -355,3 +450,3 @@ var prevCursorPosition = selectionStart;

prevCursorPosition--;
}this.setCaretPosition(el, prevCursorPosition);
}this.setPatchedCaretPosition(el, prevCursorPosition);
}

@@ -358,0 +453,0 @@ }

{
"name": "react-number-format",
"description": "React component to format number in an input or as a text.",
"version": "1.2.1",
"version": "2.0.0-alpha",
"main": "lib/number_format.js",

@@ -6,0 +6,0 @@ "author": "Sudhanshu Yadav",

@@ -1,2 +0,13 @@

//const React = require('react');
/**
* 1. Validate thousand separators and decimals throw error
* 2. Thousand separator just have value true or any other string
* 3. Decimal separator should be defined only as string
* 4. Decimal precision should be only defined as number
* 5. If user don't want floating numbers set decimalPrecision to 0
* 6. User can pass value as floating point numbers or string, if user passes string decimal separator in string should match to provided decimalSeparator
* 7. Add formattedValue, numeric value, value with string in event object and not as parameters so that getting values should look consistent
* 8. dont use parseFloat that will not able to parse 2^23
* 9. Always have decimal precision
* 10. isAllowed props to validate input and block if returns false
*/
import PropTypes from 'prop-types';

@@ -9,6 +20,19 @@ import React from 'react';

function removeLeadingZero(numStr) {
//remove leading zeros
return numStr.replace(/^0+/,'') || '0';
}
function limitToPrecision(numStr, precision) {
let str = ''
for (let i=0; i<=precision - 1; i++) {
str += numStr[i] || '0'
}
return str;
}
const propTypes = {
thousandSeparator: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
decimalSeparator: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
decimalPrecision: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]),
thousandSeparator: PropTypes.oneOfType([PropTypes.string, PropTypes.oneOf([true])]),
decimalSeparator: PropTypes.string,
decimalPrecision: PropTypes.number,
displayType: PropTypes.oneOf(['input', 'text']),

@@ -29,3 +53,4 @@ prefix: PropTypes.string,

onKeyDown: PropTypes.func,
onChange: PropTypes.func
onChange: PropTypes.func,
isAllowed: PropTypes.func
};

@@ -36,4 +61,4 @@

decimalSeparator: '.',
decimalPrecision: false,
allowNegative: true
allowNegative: true,
isAllowed: function() {return true;}
};

@@ -44,4 +69,5 @@

super(props);
const value = this.optimizeValueProp(props);
this.state = {
value: this.formatInput(props.value).formattedValue
value: this.formatInput(value).formattedValue
}

@@ -52,26 +78,63 @@ this.onChange = this.onChange.bind(this);

componentWillReceiveProps(newProps) {
if(newProps.value !== this.props.value) {
this.setState({
value : this.formatInput(newProps.value).formattedValue
});
}
componentDidUpdate(prevProps, prevState) {
this.updateValueIfRequired(prevProps, prevState);
}
getSeparators() {
let {thousandSeparator, decimalSeparator} = this.props;
if (thousandSeparator === true) {
thousandSeparator = ','
updateValueIfRequired(prevProps) {
const {props, state} = this;
if(prevProps !== props) {
const stateValue = state.value;
let value = this.optimizeValueProp(props);
if (value === undefined) value = stateValue;
const {formattedValue} = this.formatInput(value);
if (formattedValue !== stateValue) {
this.setState({
value : this.formatInput(value).formattedValue
})
}
}
}
if (decimalSeparator && thousandSeparator && typeof decimalSeparator !== 'string') {
decimalSeparator = thousandSeparator === '.' ? ',' : '.';
getFloatValue(num) {
const {decimalSeparator} = this.props;
return parseFloat(num.replace(decimalSeparator, '.')) || 0;
}
optimizeValueProp(props) {
const {decimalSeparator} = this.getSeparators(props);
let {value, decimalPrecision, format} = props;
if (format || value === undefined) return value;
const isNumber = typeof value === 'number';
if (isNumber) value = value.toString();
//correct decimal separator
if (decimalSeparator && isNumber) {
value = value.replace('.', decimalSeparator);
}
if (thousandSeparator === '.') {
decimalSeparator = ',';
//if decimalPrecision is 0 remove decimalNumbers
if (decimalPrecision === 0) return value.split(decimalSeparator)[0]
return value;
}
getSeparators(props) {
let {thousandSeparator, decimalSeparator, decimalPrecision} = props || this.props;
if (thousandSeparator === true) {
thousandSeparator = ','
}
if (decimalSeparator === true) {
decimalSeparator = '.'
if (decimalSeparator === thousandSeparator) {
throw new Error(`
Decimal separator can\'t be same as thousand separator.\n
thousandSeparator: ${thousandSeparator} (thousandSeparator = {true} is same as thousandSeparator = ",")
decimalSeparator: ${decimalSeparator} (default value for decimalSeparator is .)
`);
}

@@ -85,6 +148,6 @@

getNumberRegex(g, ignoreDecimalSeperator) {
const {format} = this.props;
getNumberRegex(g, ignoreDecimalSeparator) {
const {format, decimalPrecision} = this.props;
const {decimalSeparator} = this.getSeparators();
return new RegExp('\\d' + (decimalSeparator && !ignoreDecimalSeperator && !format ? '|' + escapeRegExp(decimalSeparator) : ''), g ? 'g' : undefined);
return new RegExp('\\d' + (decimalSeparator && decimalPrecision !== 0 && !ignoreDecimalSeparator && !format ? '|' + escapeRegExp(decimalSeparator) : ''), g ? 'g' : undefined);
}

@@ -117,2 +180,12 @@

setPatchedCaretPosition(el, caretPos) {
/*
setting caret position within timeout of 0ms is required for mobile chrome,
otherwise browser resets the caret position after we set it
We are also setting it without timeout so that in normal browser we don't see the flickering
*/
this.setCaretPosition(el, caretPos);
setTimeout(() => this.setCaretPosition(el, caretPos), 0);
}
formatWithPattern(str) {

@@ -161,9 +234,9 @@ const {format,mask} = this.props;

const valMatch = val && val.match(numRegex);
if (!valMatch && removeNegative) {
return {value :'', formattedValue: ''}
return {value :'', formattedValue: ''}
} else if (!valMatch && hasNegative) {
return {value :'', formattedValue: '-'}
return {value :'', formattedValue: '-'}
} else if (!valMatch) {
return {value :'', formattedValue: (maskPattern ? '' : '')}
return {value :'', formattedValue: (maskPattern ? '' : '')}
}

@@ -184,26 +257,18 @@

else{
let beforeDecimal = formattedValue, afterDecimal = '';
const hasDecimals = formattedValue.indexOf(decimalSeparator) !== -1 || decimalPrecision !== false;
if(decimalSeparator && hasDecimals) {
let parts;
if (decimalPrecision !== false) {
const precision = decimalPrecision === true ? 2 : decimalPrecision;
if (decimalSeparator !== '.') {
// Replace custom decimalSeparator with '.' for parseFloat function
parts = parseFloat(formattedValue.replace(decimalSeparator, '.')).toFixed(precision)
// Put custom decimalSeparator back
parts = parts.replace('.', decimalSeparator);
} else {
parts = parseFloat(formattedValue).toFixed(precision)
}
parts = parts.split(decimalSeparator);
} else {
parts = formattedValue.split(decimalSeparator);
}
beforeDecimal = parts[0];
afterDecimal = parts[1];
}
const hasDecimalSeparator = formattedValue.indexOf(decimalSeparator) !== -1 || decimalPrecision;
const parts = formattedValue.split(decimalSeparator);
let beforeDecimal = parts[0];
let afterDecimal = parts[1] || '';
//remove leading zeros from number before decimal
beforeDecimal = removeLeadingZero(beforeDecimal);
//apply decimal precision if its defined
if (decimalPrecision !== undefined) afterDecimal = limitToPrecision(afterDecimal, decimalPrecision);
if(thousandSeparator) {
beforeDecimal = beforeDecimal.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + thousandSeparator);
}
//add prefix and suffix

@@ -215,3 +280,3 @@ if(prefix) beforeDecimal = prefix + beforeDecimal;

formattedValue = beforeDecimal + (hasDecimals && decimalSeparator || '') + afterDecimal;
formattedValue = beforeDecimal + (hasDecimalSeparator && decimalSeparator || '') + afterDecimal;
}

@@ -230,4 +295,6 @@

j=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) j++;

@@ -244,16 +311,21 @@ j++;

const inputValue = el.value;
const {formattedValue,value} = this.formatInput(inputValue);
let cursorPos = el.selectionStart;
const {isAllowed} = this.props;
const lastValue = this.state.value;
let {formattedValue, value} = this.formatInput(inputValue);
const cursorPos = this.getCursorPosition(inputValue, formattedValue, el.selectionStart);
//set caret position befor setState
//this.setPatchedCaretPosition(el, cursorPos);
if (!isAllowed(formattedValue, value, this.getFloatValue(value))) {
formattedValue = lastValue;
}
//change the state
this.setState({value : formattedValue},()=>{
cursorPos = this.getCursorPosition(inputValue, formattedValue, cursorPos );
/*
setting caret position within timeout of 0ms is required for mobile chrome,
otherwise browser resets the caret position after we set it
We are also setting it without timeout so that in normal browser we don't see the flickering
*/
this.setCaretPosition(el, cursorPos);
setTimeout(() => this.setCaretPosition(el, cursorPos), 0);
if(callback) callback(e,value);
//reset again after setState so if formattedValue is other then
this.setPatchedCaretPosition(el, cursorPos);
if(callback && formattedValue !== lastValue) callback(e, value);
});

@@ -271,17 +343,22 @@

const {decimalPrecision} = this.props;
const {key} = e;
const numRegex = this.getNumberRegex(false, decimalPrecision !== false);
const {key, which, keyCode} = e;
const numRegex = this.getNumberRegex(false, decimalPrecision !== undefined);
console.log(numRegex.toString(), key, which, keyCode);
console.log(e);
const negativeRegex = new RegExp('-');
//Handle backspace and delete against non numerical/decimal characters
if(selectionEnd - selectionStart === 0) {
console.log('coming here');
if (key === 'Delete' && !numRegex.test(value[selectionStart]) && !negativeRegex.test(value[selectionStart])) {
console.log('delete');
e.preventDefault();
let nextCursorPosition = selectionStart;
while (!numRegex.test(value[nextCursorPosition]) && nextCursorPosition < value.length) nextCursorPosition++;
this.setCaretPosition(el, nextCursorPosition);
this.setPatchedCaretPosition(el, nextCursorPosition);
} else if (key === 'Backspace' && !numRegex.test(value[selectionStart - 1]) && !negativeRegex.test(value[selectionStart-1])) {
console.log('Backspace');
e.preventDefault();
let prevCursorPosition = selectionStart;
while (!numRegex.test(value[prevCursorPosition - 1]) && prevCursorPosition > 0) prevCursorPosition--;
this.setCaretPosition(el, prevCursorPosition);
this.setPatchedCaretPosition(el, prevCursorPosition);
}

@@ -330,2 +407,2 @@ }

module.exports = NumberFormat;
module.exports = NumberFormat;

@@ -76,3 +76,3 @@ import React from 'react';

const wrapper = shallow(<NumberFormat thousandSeparator={true} prefix={'$'} />);
wrapper.find('input').simulate('change', getCustomEvent('-2456981.89'));

@@ -84,3 +84,3 @@

expect(wrapper.state().value).toEqual('-');
});

@@ -90,3 +90,3 @@

const wrapper = shallow(<NumberFormat format="#### #### #### ####" />);
wrapper.find('input').simulate('change', getCustomEvent('-2456981'));

@@ -99,3 +99,3 @@

const wrapper = shallow(<NumberFormat thousandSeparator={true} prefix={'$'} />);
wrapper.find('input').simulate('change', getCustomEvent('--2456981.89'));

@@ -107,3 +107,3 @@

expect(wrapper.state().value).toEqual('');
});

@@ -113,3 +113,3 @@

const wrapper = shallow(<NumberFormat thousandSeparator={true} prefix={'$'}/>);
wrapper.find('input').simulate('change', getCustomEvent('24569-81.89'));

@@ -150,2 +150,12 @@

it('should throw error when decimal separator and thousand separator are same', () => {
expect(() => {
shallow(<NumberFormat thousandSeparator={'.'} prefix={'$'} />);
}).toThrow()
expect(() => {
shallow(<NumberFormat thousandSeparator={','} decimalSeparator={','} prefix={'$'} />);
}).toThrow()
});
it('should support decimal precision with custom decimal separator', () => {

@@ -159,2 +169,41 @@ const wrapper = shallow(<NumberFormat thousandSeparator={'.'} decimalSeparator={','} decimalPrecision={2} />);

it('should allow floating/integer numbers as values and do proper formatting', () => {
const wrapper = shallow(<NumberFormat value={12345.67} />, { lifecycleExperimental: true });
expect(wrapper.state().value).toEqual('12345.67');
wrapper.setProps({thousandSeparator: true});
expect(wrapper.state().value).toEqual('12,345.67');
wrapper.setProps({thousandSeparator: '.', decimalSeparator: ','});
expect(wrapper.state().value).toEqual('12.345,67');
wrapper.setProps({thousandSeparator: '.', decimalSeparator: ',', decimalPrecision: 0});
expect(wrapper.state().value).toEqual('12.345');
});
it('should update formatted value if any of the props changes', () => {
const wrapper = shallow(<NumberFormat value={12345.67} />, { lifecycleExperimental: true });
expect(wrapper.state().value).toEqual('12345.67');
wrapper.setProps({thousandSeparator: true});
expect(wrapper.state().value).toEqual('12,345.67');
wrapper.setProps({thousandSeparator: '.', decimalSeparator: ','});
expect(wrapper.state().value).toEqual('12.345,67');
wrapper.setProps({thousandSeparator: '.', decimalSeparator: ',', decimalPrecision: 0});
expect(wrapper.state().value).toEqual('12.345');
});
it('should allow bigger number than 2^53 and do proper formatting', () => {
const wrapper = shallow(<NumberFormat thousandSeparator="." decimalSeparator="," />);
const input = wrapper.find('input');
input.simulate('change', getCustomEvent('981273724234817383478127'));
expect(wrapper.state().value).toEqual('981.273.724.234.817.383.478.127');
input.simulate('change', getCustomEvent('981273724234817383478,127'));
expect(wrapper.state().value).toEqual('981.273.724.234.817.383.478,127');
})
it('should have proper intermediate formatting', () => {

@@ -252,3 +301,17 @@ const wrapper = shallow(<NumberFormat format="#### #### #### ####" />);

it('sould not allow decimal numbers if decimal precision is set to 0', () => {
const wrapper = shallow(<NumberFormat thousandSeparator={true} decimalPrecision={0}/>, {lifecycleExperimental: true});
const input = wrapper.find('input');
//case 1 - decimal precision set to 0
input.simulate('change', getCustomEvent('4111.'));
expect(wrapper.state().value).toEqual('4,111');
//case 2 - It should remove decimal values if passed value props as decimal values
wrapper.setProps({value: 1234.78});
expect(wrapper.state().value).toEqual('1,234');
})
it('should not round by default', () => {

@@ -287,3 +350,3 @@ const wrapper = shallow(<NumberFormat/>);

wrapper.setProps({format: '#### #### #### ####', mask: '_', thousandSeparator: false, decimalSeparator: false});
wrapper.setProps({format: '#### #### #### ####', mask: '_'});
input.simulate('change', getCustomEvent('41111 1'));

@@ -330,3 +393,3 @@ expect(input.get(0).value).toEqual('4111 11__ ____ ____');

it('should round to 2 decimals if passed true', () => {
const wrapper = shallow(<NumberFormat value="4111" displayType={'text'} decimalPrecision={true} />);
const wrapper = shallow(<NumberFormat value="4111" displayType={'text'} decimalPrecision={2} />);
expect(wrapper.find('span').text()).toEqual('4111.00');

@@ -333,0 +396,0 @@ });

@@ -7,3 +7,3 @@ module.exports = {

},
devtool: "eval",
devtool: "cheap-module-eval-source-map",
debug: true,

@@ -10,0 +10,0 @@ output: {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc