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.0.2 to 1.1.0-alpha2

143

dist/react-number-format.js
/*!
* react-number-format - 1.0.2
* react-number-format - 1.1.0-alpha2
* Author : Sudhanshu Yadav

@@ -93,4 +93,5 @@ * Copyright (c) 2016,2017 to Sudhanshu Yadav - ignitersworld.com , released under the MIT license.

var propTypes = {
thousandSeparator: _react.PropTypes.oneOf([',', '.', true, false]),
decimalSeparator: _react.PropTypes.oneOf([',', '.', true, false]),
thousandSeparator: _react.PropTypes.oneOfType([_react.PropTypes.string, _react.PropTypes.bool]),
decimalSeparator: _react.PropTypes.oneOfType([_react.PropTypes.string, _react.PropTypes.bool]),
decimalPrecision: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.bool]),
displayType: _react.PropTypes.oneOf(['input', 'text']),

@@ -101,3 +102,4 @@ prefix: _react.PropTypes.string,

mask: _react.PropTypes.string,
value: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string])
value: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]),
customInput: _react.PropTypes.func
};

@@ -107,3 +109,4 @@

displayType: 'input',
decimalSeparator: '.'
decimalSeparator: '.',
decimalPrecision: false
};

@@ -124,2 +127,3 @@

_this.onInput = _this.onInput.bind(_this);
_this.onKeyDown = _this.onKeyDown.bind(_this);
return _this;

@@ -140,5 +144,5 @@ }

value: function getSeparators() {
var _props = this.props;
var thousandSeparator = _props.thousandSeparator;
var decimalSeparator = _props.decimalSeparator;
var _props = this.props,
thousandSeparator = _props.thousandSeparator,
decimalSeparator = _props.decimalSeparator;

@@ -149,4 +153,4 @@ if (thousandSeparator === true) {

if (decimalSeparator && thousandSeparator) {
decimalSeparator = thousandSeparator === ',' ? '.' : ',';
if (decimalSeparator && thousandSeparator && typeof decimalSeparator !== 'string') {
decimalSeparator = thousandSeparator === '.' ? ',' : '.';
}

@@ -165,13 +169,11 @@

key: 'getNumberRegex',
value: function getNumberRegex(g) {
var _getSeparators = this.getSeparators();
value: function getNumberRegex(g, ignoreDecimalSeperator) {
var _getSeparators = this.getSeparators(),
decimalSeparator = _getSeparators.decimalSeparator;
var decimalSeparator = _getSeparators.decimalSeparator;
return new RegExp('\\d' + (decimalSeparator ? '|' + escapeRegExp(decimalSeparator) : ''), g ? 'g' : undefined);
return new RegExp('\\d' + (decimalSeparator && !ignoreDecimalSeperator ? '|' + escapeRegExp(decimalSeparator) : ''), g ? 'g' : undefined);
}
}, {
key: 'setCaretPosition',
value: function setCaretPosition(caretPos) {
var el = this.refs.input;
value: function setCaretPosition(el, caretPos) {
el.value = el.value;

@@ -203,5 +205,5 @@ // ^ this is used to not only get "focus", but

value: function formatWithPattern(str) {
var _props2 = this.props;
var format = _props2.format;
var mask = _props2.mask;
var _props2 = this.props,
format = _props2.format,
mask = _props2.mask;

@@ -230,12 +232,13 @@ if (!format) return str;

value: function formatInput(val) {
var _props3 = this.props;
var prefix = _props3.prefix;
var suffix = _props3.suffix;
var mask = _props3.mask;
var format = _props3.format;
var _props3 = this.props,
prefix = _props3.prefix,
suffix = _props3.suffix,
mask = _props3.mask,
format = _props3.format;
var _getSeparators2 = this.getSeparators();
var _getSeparators2 = this.getSeparators(),
thousandSeparator = _getSeparators2.thousandSeparator,
decimalSeparator = _getSeparators2.decimalSeparator;
var thousandSeparator = _getSeparators2.thousandSeparator;
var decimalSeparator = _getSeparators2.decimalSeparator;
var decimalPrecision = this.props.decimalPrecision;

@@ -263,5 +266,11 @@ var maskPattern = format && typeof format == 'string' && !!mask;

afterDecimal = '';
var hasDecimals = formattedValue.indexOf(decimalSeparator) !== -1;
var hasDecimals = formattedValue.indexOf(decimalSeparator) !== -1 || decimalPrecision !== false;
if (decimalSeparator && hasDecimals) {
var parts = formattedValue.split(decimalSeparator);
var parts = void 0;
if (decimalPrecision !== false) {
var precision = decimalPrecision === true ? 2 : decimalPrecision;
parts = parseFloat(formattedValue).toFixed(precision).split(decimalSeparator);
} else {
parts = formattedValue.split(decimalSeparator);
}
beforeDecimal = parts[0];

@@ -298,6 +307,2 @@ afterDecimal = parts[1];

//check if there is no number before caret position
while (j > 0 && formattedValue[j]) {
if (!formattedValue[j - 1].match(numRegex)) j--;else break;
}
return j;

@@ -311,15 +316,21 @@ }

e.persist();
var inputValue = e.target.value;
var el = e.target;
var inputValue = el.value;
var _formatInput = this.formatInput(inputValue);
var _formatInput = this.formatInput(inputValue),
formattedValue = _formatInput.formattedValue,
value = _formatInput.value;
var formattedValue = _formatInput.formattedValue;
var value = _formatInput.value;
var cursorPos = el.selectionStart;
var cursorPos = this.refs.input.selectionStart;
//change the state
this.setState({ value: formattedValue }, function () {
cursorPos = _this2.getCursorPosition(inputValue, formattedValue, cursorPos);
_this2.setCaretPosition(cursorPos);
/*
setting caret position within timeout of 0ms is required for mobile chrome,
otherwise browser resets the caret position after we set it
*/
setTimeout(function () {
return _this2.setCaretPosition(el, cursorPos);
}, 0);
if (callback) callback(e, value);

@@ -341,2 +352,32 @@ });

}, {
key: 'onKeyDown',
value: function onKeyDown(e) {
var el = e.target;
var selectionStart = el.selectionStart,
selectionEnd = el.selectionEnd,
value = el.value;
var decimalPrecision = this.props.decimalPrecision;
var key = e.key;
var numRegex = this.getNumberRegex(false, decimalPrecision !== false);
//Handle backspace and delete against non numerical/decimal characters
if (selectionEnd - selectionStart === 0) {
if (key === 'Delete' && !numRegex.test(value[selectionStart])) {
e.preventDefault();
var nextCursorPosition = selectionStart;
while (!numRegex.test(value[nextCursorPosition]) && nextCursorPosition < value.length) {
nextCursorPosition++;
}this.setCaretPosition(el, nextCursorPosition);
} else if (key === 'Backspace' && !numRegex.test(value[selectionStart - 1])) {
e.preventDefault();
var prevCursorPosition = selectionStart;
while (!numRegex.test(value[prevCursorPosition - 1]) && prevCursorPosition > 0) {
prevCursorPosition--;
}this.setCaretPosition(el, prevCursorPosition);
}
}
if (this.props.onKeyDown) this.props.onKeyDown(e);
}
}, {
key: 'render',

@@ -350,2 +391,10 @@ value: function render() {

var inputProps = _extends({}, props, {
type: 'tel',
value: this.state.value,
onInput: this.onChange,
onChange: this.onChange,
onKeyDown: this.onKeyDown
});
if (this.props.displayType === 'text') {

@@ -357,10 +406,8 @@ return _react2.default.createElement(

);
} else if (this.props.customInput) {
var CustomInput = this.props.customInput;
return _react2.default.createElement(CustomInput, inputProps);
}
return _react2.default.createElement('input', _extends({}, props, {
type: 'tel',
value: this.state.value,
ref: 'input',
onInput: this.onChange,
onChange: this.onChange
}));
return _react2.default.createElement('input', inputProps);
}

@@ -367,0 +414,0 @@ }]);

/*!
* react-number-format - 1.0.2
* react-number-format - 1.1.0-alpha2
* 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},p=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}}(),f=r(2),l=n(f),c={thousandSeparator:f.PropTypes.oneOf([",",".",!0,!1]),decimalSeparator:f.PropTypes.oneOf([",",".",!0,!1]),displayType:f.PropTypes.oneOf(["input","text"]),prefix:f.PropTypes.string,suffix:f.PropTypes.string,format:f.PropTypes.oneOfType([f.PropTypes.string,f.PropTypes.func]),mask:f.PropTypes.string,value:f.PropTypes.oneOfType([f.PropTypes.number,f.PropTypes.string])},h={displayType:"input",decimalSeparator:"."},v=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.onInput=r.onInput.bind(r),r}return i(t,e),p(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&&(r=","===t?".":","),r===!0&&(r="."),{decimalSeparator:r,thousandSeparator:t}}},{key:"getNumberRegex",value:function(e){var t=this.getSeparators(),r=t.decimalSeparator;return new RegExp("\\d"+(r?"|"+u(r):""),e?"g":void 0)}},{key:"setCaretPosition",value:function(e){var t=this.refs.input;if(t.value=t.value,null!==t){if(t.createTextRange){var r=t.createTextRange();return r.move("character",e),r.select(),!0}return t.selectionStart||0===t.selectionStart?(t.focus(),t.setSelectionRange(e,e),!0):(t.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 p=i.lastIndexOf("#");return n?i.replace(/#/g,n):i.substring(0,a+1)+(p!==-1?i.substring(p+1,i.length):"")}},{key:"formatInput",value:function(e){var t=this.props,r=t.prefix,n=t.suffix,o=(t.mask,t.format),a=this.getSeparators(),i=a.thousandSeparator,u=a.decimalSeparator,s=this.getNumberRegex(!0);if("number"==typeof e&&(e+=""),!e||!e.match(s))return{value:"",formattedValue:""};var p=e.match(s).join(""),f=p;if(o)"string"==typeof o?f=this.formatWithPattern(f):"function"==typeof o&&(f=o(f));else{var l=f,c="",h=f.indexOf(u)!==-1;if(u&&h){var v=f.split(u);l=v[0],c=v[1]}i&&(l=l.replace(/(\d)(?=(\d{3})+(?!\d))/g,"$1"+i)),r&&(l=r+l),n&&(c+=n),f=l+(h&&u||"")+c}return{value:f.match(s).join(""),formattedValue:f}}},{key:"getCursorPosition",value:function(e,t,r){for(var n=this.getNumberRegex(),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++}for(;o>0&&t[o]&&!t[o-1].match(n);)o--;return o}},{key:"onChangeHandler",value:function(e,t){var r=this;e.persist();var n=e.target.value,o=this.formatInput(n),a=o.formattedValue,i=o.value,u=this.refs.input.selectionStart;return this.setState({value:a},function(){u=r.getCursorPosition(n,a,u),r.setCaretPosition(u),t&&t(e,i)}),i}},{key:"onChange",value:function(e){this.onChangeHandler(e,this.props.onChange)}},{key:"onInput",value:function(e){this.onChangeHandler(e,this.props.onInput)}},{key:"render",value:function(){var e=s({},this.props);return Object.keys(c).forEach(function(t){delete e[t]}),"text"===this.props.displayType?l["default"].createElement("span",e,this.state.value):l["default"].createElement("input",s({},e,{type:"tel",value:this.state.value,ref:"input",onInput:this.onChange,onChange:this.onChange}))}}]),t}(l["default"].Component);v.propTypes=c,v.defaultProps=h,e.exports=v},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 s(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}var p=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},u=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}}(),f=r(2),l=n(f),c={thousandSeparator:f.PropTypes.oneOfType([f.PropTypes.string,f.PropTypes.bool]),decimalSeparator:f.PropTypes.oneOfType([f.PropTypes.string,f.PropTypes.bool]),decimalPrecision:f.PropTypes.oneOfType([f.PropTypes.number,f.PropTypes.bool]),displayType:f.PropTypes.oneOf(["input","text"]),prefix:f.PropTypes.string,suffix:f.PropTypes.string,format:f.PropTypes.oneOfType([f.PropTypes.string,f.PropTypes.func]),mask:f.PropTypes.string,value:f.PropTypes.oneOfType([f.PropTypes.number,f.PropTypes.string]),customInput:f.PropTypes.func},y={displayType:"input",decimalSeparator:".",decimalPrecision:!1},h=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.onInput=r.onInput.bind(r),r.onKeyDown=r.onKeyDown.bind(r),r}return i(t,e),u(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?",":"."),r===!0&&(r="."),{decimalSeparator:r,thousandSeparator:t}}},{key:"getNumberRegex",value:function(e,t){var r=this.getSeparators(),n=r.decimalSeparator;return new RegExp("\\d"+(n&&!t?"|"+s(n):""),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,s=0,p=e.length;s<p;s++)s<o&&(a=i.indexOf("#"),i=i.replace("#",e[s]));var u=i.lastIndexOf("#");return n?i.replace(/#/g,n):i.substring(0,a+1)+(u!==-1?i.substring(u+1,i.length):"")}},{key:"formatInput",value:function(e){var t=this.props,r=t.prefix,n=t.suffix,o=(t.mask,t.format),a=this.getSeparators(),i=a.thousandSeparator,s=a.decimalSeparator,p=this.props.decimalPrecision,u=this.getNumberRegex(!0);if("number"==typeof e&&(e+=""),!e||!e.match(u))return{value:"",formattedValue:""};var f=e.match(u).join(""),l=f;if(o)"string"==typeof o?l=this.formatWithPattern(l):"function"==typeof o&&(l=o(l));else{var c=l,y="",h=l.indexOf(s)!==-1||p!==!1;if(s&&h){var v=void 0;if(p!==!1){var d=p===!0?2:p;v=parseFloat(l).toFixed(d).split(s)}else v=l.split(s);c=v[0],y=v[1]}i&&(c=c.replace(/(\d)(?=(\d{3})+(?!\d))/g,"$1"+i)),r&&(c=r+c),n&&(y+=n),l=c+(h&&s||"")+y}return{value:l.match(u).join(""),formattedValue:l}}},{key:"getCursorPosition",value:function(e,t,r){for(var n=this.getNumberRegex(),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,s=a.value,p=n.selectionStart;return this.setState({value:i},function(){p=r.getCursorPosition(o,i,p),setTimeout(function(){return r.setCaretPosition(n,p)},0),t&&t(e,s)}),s}},{key:"onChange",value:function(e){this.onChangeHandler(e,this.props.onChange)}},{key:"onInput",value:function(e){this.onChangeHandler(e,this.props.onInput)}},{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,s=this.getNumberRegex(!1,a!==!1);if(n-r===0)if("Delete"!==i||s.test(o[r])){if("Backspace"===i&&!s.test(o[r-1])){e.preventDefault();for(var p=r;!s.test(o[p-1])&&p>0;)p--;this.setCaretPosition(t,p)}}else{e.preventDefault();for(var u=r;!s.test(o[u])&&u<o.length;)u++;this.setCaretPosition(t,u)}this.props.onKeyDown&&this.props.onKeyDown(e)}},{key:"render",value:function(){var e=p({},this.props);Object.keys(c).forEach(function(t){delete e[t]});var t=p({},e,{type:"tel",value:this.state.value,onInput:this.onChange,onChange:this.onChange,onKeyDown:this.onKeyDown});if("text"===this.props.displayType)return l.default.createElement("span",e,this.state.value);if(this.props.customInput){var r=this.props.customInput;return l.default.createElement(r,t)}return l.default.createElement("input",t)}}]),t}(l.default.Component);h.propTypes=c,h.defaultProps=y,e.exports=h},function(t,r){t.exports=e}])});
import React from 'react';
import ReactDOM from 'react-dom';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import NumberFormat from '../../src/number_format';
import TextField from 'material-ui/TextField';

@@ -49,5 +51,25 @@ class App extends React.Component {

<h3>
Decimal precision : Format currency in input with decimal precision
</h3>
<NumberFormat thousandSeparator={true} decimalPrecision={true} prefix={'$'}/>
</div>
<div className="example">
<h3>
Custom thousand seperator : Format currency in input
</h3>
<NumberFormat thousandSeparator={'.'} decimalSeparator={','} prefix={'$'} />
<div>
ThousandSeperator: '.', decimalSeparator=','
</div>
<div>
<NumberFormat thousandSeparator={"."} decimalSeparator={','} prefix={'$'} />
</div>
<br/>
<div>
ThousandSeperator: ' ', decimalSeparator='.'
</div>
<div>
<NumberFormat thousandSeparator={" "} decimalSeparator={'.'} prefix={'$'} />
</div>
</div>

@@ -75,2 +97,10 @@

</div>
<div className="example">
<h3>
Custom input : Format credit card number
</h3>
<NumberFormat customInput={TextField} format="#### #### #### ####"/>
</div>
</div>

@@ -81,3 +111,8 @@ )

const ThemedApp = () => {
return (<MuiThemeProvider>
<App />
</MuiThemeProvider>);
};
ReactDOM.render(<App />, document.getElementById('app'));
ReactDOM.render(<ThemedApp />, document.getElementById('app'));

@@ -25,4 +25,5 @@ 'use strict';

var propTypes = {
thousandSeparator: _react.PropTypes.oneOf([',', '.', true, false]),
decimalSeparator: _react.PropTypes.oneOf([',', '.', true, false]),
thousandSeparator: _react.PropTypes.oneOfType([_react.PropTypes.string, _react.PropTypes.bool]),
decimalSeparator: _react.PropTypes.oneOfType([_react.PropTypes.string, _react.PropTypes.bool]),
decimalPrecision: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.bool]),
displayType: _react.PropTypes.oneOf(['input', 'text']),

@@ -33,3 +34,4 @@ prefix: _react.PropTypes.string,

mask: _react.PropTypes.string,
value: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string])
value: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]),
customInput: _react.PropTypes.func
};

@@ -39,3 +41,4 @@

displayType: 'input',
decimalSeparator: '.'
decimalSeparator: '.',
decimalPrecision: false
};

@@ -56,2 +59,3 @@

_this.onInput = _this.onInput.bind(_this);
_this.onKeyDown = _this.onKeyDown.bind(_this);
return _this;

@@ -72,5 +76,5 @@ }

value: function getSeparators() {
var _props = this.props;
var thousandSeparator = _props.thousandSeparator;
var decimalSeparator = _props.decimalSeparator;
var _props = this.props,
thousandSeparator = _props.thousandSeparator,
decimalSeparator = _props.decimalSeparator;

@@ -81,4 +85,4 @@ if (thousandSeparator === true) {

if (decimalSeparator && thousandSeparator) {
decimalSeparator = thousandSeparator === ',' ? '.' : ',';
if (decimalSeparator && thousandSeparator && typeof decimalSeparator !== 'string') {
decimalSeparator = thousandSeparator === '.' ? ',' : '.';
}

@@ -97,13 +101,11 @@

key: 'getNumberRegex',
value: function getNumberRegex(g) {
var _getSeparators = this.getSeparators();
value: function getNumberRegex(g, ignoreDecimalSeperator) {
var _getSeparators = this.getSeparators(),
decimalSeparator = _getSeparators.decimalSeparator;
var decimalSeparator = _getSeparators.decimalSeparator;
return new RegExp('\\d' + (decimalSeparator ? '|' + escapeRegExp(decimalSeparator) : ''), g ? 'g' : undefined);
return new RegExp('\\d' + (decimalSeparator && !ignoreDecimalSeperator ? '|' + escapeRegExp(decimalSeparator) : ''), g ? 'g' : undefined);
}
}, {
key: 'setCaretPosition',
value: function setCaretPosition(caretPos) {
var el = this.refs.input;
value: function setCaretPosition(el, caretPos) {
el.value = el.value;

@@ -135,5 +137,5 @@ // ^ this is used to not only get "focus", but

value: function formatWithPattern(str) {
var _props2 = this.props;
var format = _props2.format;
var mask = _props2.mask;
var _props2 = this.props,
format = _props2.format,
mask = _props2.mask;

@@ -162,12 +164,13 @@ if (!format) return str;

value: function formatInput(val) {
var _props3 = this.props;
var prefix = _props3.prefix;
var suffix = _props3.suffix;
var mask = _props3.mask;
var format = _props3.format;
var _props3 = this.props,
prefix = _props3.prefix,
suffix = _props3.suffix,
mask = _props3.mask,
format = _props3.format;
var _getSeparators2 = this.getSeparators();
var _getSeparators2 = this.getSeparators(),
thousandSeparator = _getSeparators2.thousandSeparator,
decimalSeparator = _getSeparators2.decimalSeparator;
var thousandSeparator = _getSeparators2.thousandSeparator;
var decimalSeparator = _getSeparators2.decimalSeparator;
var decimalPrecision = this.props.decimalPrecision;

@@ -195,5 +198,11 @@ var maskPattern = format && typeof format == 'string' && !!mask;

afterDecimal = '';
var hasDecimals = formattedValue.indexOf(decimalSeparator) !== -1;
var hasDecimals = formattedValue.indexOf(decimalSeparator) !== -1 || decimalPrecision !== false;
if (decimalSeparator && hasDecimals) {
var parts = formattedValue.split(decimalSeparator);
var parts = void 0;
if (decimalPrecision !== false) {
var precision = decimalPrecision === true ? 2 : decimalPrecision;
parts = parseFloat(formattedValue).toFixed(precision).split(decimalSeparator);
} else {
parts = formattedValue.split(decimalSeparator);
}
beforeDecimal = parts[0];

@@ -230,6 +239,2 @@ afterDecimal = parts[1];

//check if there is no number before caret position
while (j > 0 && formattedValue[j]) {
if (!formattedValue[j - 1].match(numRegex)) j--;else break;
}
return j;

@@ -243,15 +248,21 @@ }

e.persist();
var inputValue = e.target.value;
var el = e.target;
var inputValue = el.value;
var _formatInput = this.formatInput(inputValue);
var _formatInput = this.formatInput(inputValue),
formattedValue = _formatInput.formattedValue,
value = _formatInput.value;
var formattedValue = _formatInput.formattedValue;
var value = _formatInput.value;
var cursorPos = el.selectionStart;
var cursorPos = this.refs.input.selectionStart;
//change the state
this.setState({ value: formattedValue }, function () {
cursorPos = _this2.getCursorPosition(inputValue, formattedValue, cursorPos);
_this2.setCaretPosition(cursorPos);
/*
setting caret position within timeout of 0ms is required for mobile chrome,
otherwise browser resets the caret position after we set it
*/
setTimeout(function () {
return _this2.setCaretPosition(el, cursorPos);
}, 0);
if (callback) callback(e, value);

@@ -273,2 +284,32 @@ });

}, {
key: 'onKeyDown',
value: function onKeyDown(e) {
var el = e.target;
var selectionStart = el.selectionStart,
selectionEnd = el.selectionEnd,
value = el.value;
var decimalPrecision = this.props.decimalPrecision;
var key = e.key;
var numRegex = this.getNumberRegex(false, decimalPrecision !== false);
//Handle backspace and delete against non numerical/decimal characters
if (selectionEnd - selectionStart === 0) {
if (key === 'Delete' && !numRegex.test(value[selectionStart])) {
e.preventDefault();
var nextCursorPosition = selectionStart;
while (!numRegex.test(value[nextCursorPosition]) && nextCursorPosition < value.length) {
nextCursorPosition++;
}this.setCaretPosition(el, nextCursorPosition);
} else if (key === 'Backspace' && !numRegex.test(value[selectionStart - 1])) {
e.preventDefault();
var prevCursorPosition = selectionStart;
while (!numRegex.test(value[prevCursorPosition - 1]) && prevCursorPosition > 0) {
prevCursorPosition--;
}this.setCaretPosition(el, prevCursorPosition);
}
}
if (this.props.onKeyDown) this.props.onKeyDown(e);
}
}, {
key: 'render',

@@ -282,2 +323,10 @@ value: function render() {

var inputProps = _extends({}, props, {
type: 'tel',
value: this.state.value,
onInput: this.onChange,
onChange: this.onChange,
onKeyDown: this.onKeyDown
});
if (this.props.displayType === 'text') {

@@ -289,10 +338,8 @@ return _react2.default.createElement(

);
} else if (this.props.customInput) {
var CustomInput = this.props.customInput;
return _react2.default.createElement(CustomInput, inputProps);
}
return _react2.default.createElement('input', _extends({}, props, {
type: 'tel',
value: this.state.value,
ref: 'input',
onInput: this.onChange,
onChange: this.onChange
}));
return _react2.default.createElement('input', inputProps);
}

@@ -299,0 +346,0 @@ }]);

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

@@ -42,2 +42,3 @@ "author": "Sudhanshu Yadav",

"classnames": "^2.2.3",
"cross-env": "^3.1.4",
"eslint": "^2.5.3",

@@ -61,2 +62,3 @@ "eslint-config-standard": "^5.1.0",

"karma-webpack": "^1.7.0",
"material-ui": "^0.16.7",
"react": "^15.0.1",

@@ -63,0 +65,0 @@ "react-addons-test-utils": "^15.0.1",

@@ -20,4 +20,5 @@ # react-number-format

| ------------- |-------------| -----| -------- |
| thousandSeparator | mixed: true/false (boolean) or ,/. (string) | false | Add thousand separators on number |
| decimalSeparator | mixed: ./, (string) or true/false (boolean)| . | Support decimal point on a number |
| 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 |
| prefix | String (ex : $) | none | Add a prefix before the number |

@@ -29,5 +30,6 @@ | suffix | String (ex : /-) | none | Add a prefix after the 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. See details
| 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)
Other than this it accepts all the props which can be given to a input or span based on displayType you selected.
**Other than this it accepts all the props which can be given to a input or span based on displayType you selected.**

@@ -93,2 +95,19 @@ ### Examples

### Custom Inputs
You can easily extend your custom input with number format. But custom input should have all input props.
```jsx
import TextField from 'material-ui/TextField';
```
```jsx
<NumberFormat customInput={TextField} format="#### #### #### ####"/>
```
**Passing custom input props**
All custom input props and number input props are passed together.
```jsx
<NumberFormat hintText="Some placeholder" value={this.state.card} customInput={TextField} format="#### #### #### ####"/>
```
### Live Demo

@@ -95,0 +114,0 @@ [http://codepen.io/s-yadav/pen/bpKNMa](http://codepen.io/s-yadav/pen/bpKNMa)

@@ -9,4 +9,5 @@ //const React = require('react');

const propTypes = {
thousandSeparator: PropTypes.oneOf([',', '.', true, false]),
decimalSeparator: PropTypes.oneOf([',', '.', true, false]),
thousandSeparator: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
decimalSeparator: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
decimalPrecision: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]),
displayType: PropTypes.oneOf(['input', 'text']),

@@ -23,3 +24,4 @@ prefix: PropTypes.string,

PropTypes.string
])
]),
customInput: PropTypes.func
};

@@ -29,3 +31,4 @@

displayType: 'input',
decimalSeparator: '.'
decimalSeparator: '.',
decimalPrecision: false
};

@@ -41,2 +44,3 @@

this.onInput = this.onInput.bind(this);
this.onKeyDown = this.onKeyDown.bind(this);
}

@@ -58,4 +62,4 @@

if (decimalSeparator && thousandSeparator) {
decimalSeparator = thousandSeparator === ',' ? '.' : ',';
if (decimalSeparator && thousandSeparator && typeof decimalSeparator !== 'string') {
decimalSeparator = thousandSeparator === '.' ? ',' : '.';
}

@@ -73,32 +77,30 @@

getNumberRegex(g) {
getNumberRegex(g, ignoreDecimalSeperator) {
const {decimalSeparator} = this.getSeparators();
return new RegExp('\\d' + (decimalSeparator ? '|' + escapeRegExp(decimalSeparator) : ''), g ? 'g' : undefined);
return new RegExp('\\d' + (decimalSeparator && !ignoreDecimalSeperator ? '|' + escapeRegExp(decimalSeparator) : ''), g ? 'g' : undefined);
}
setCaretPosition(caretPos) {
const el = this.refs.input;
el.value = el.value;
// ^ this is used to not only get "focus", but
// to make sure we don't have it everything -selected-
// (it causes an issue in chrome, and having it doesn't hurt any other browser)
if (el !== null) {
if (el.createTextRange) {
const range = el.createTextRange();
range.move('character', caretPos);
range.select();
return true;
}
// (el.selectionStart === 0 added for Firefox bug)
if (el.selectionStart || el.selectionStart === 0) {
el.focus();
el.setSelectionRange(caretPos, caretPos);
return true;
}
setCaretPosition(el, caretPos) {
el.value = el.value;
// ^ this is used to not only get "focus", but
// to make sure we don't have it everything -selected-
// (it causes an issue in chrome, and having it doesn't hurt any other browser)
if (el !== null) {
if (el.createTextRange) {
const range = el.createTextRange();
range.move('character', caretPos);
range.select();
return true;
}
// (el.selectionStart === 0 added for Firefox bug)
if (el.selectionStart || el.selectionStart === 0) {
el.focus();
el.setSelectionRange(caretPos, caretPos);
return true;
}
// fail city, fortunately this never happens (as far as I've tested) :)
el.focus();
return false;
}
// fail city, fortunately this never happens (as far as I've tested) :)
el.focus();
return false;
}
}

@@ -130,3 +132,4 @@

const {prefix, suffix, mask, format} = this.props;
const {thousandSeparator, decimalSeparator} = this.getSeparators()
const {thousandSeparator, decimalSeparator} = this.getSeparators();
const {decimalPrecision} = this.props;
const maskPattern = format && typeof format == 'string' && !!mask;

@@ -154,5 +157,11 @@

let beforeDecimal = formattedValue, afterDecimal = '';
const hasDecimals = formattedValue.indexOf(decimalSeparator) !== -1;
const hasDecimals = formattedValue.indexOf(decimalSeparator) !== -1 || decimalPrecision !== false;
if(decimalSeparator && hasDecimals) {
const parts = formattedValue.split(decimalSeparator)
let parts;
if (decimalPrecision !== false) {
const precision = decimalPrecision === true ? 2 : decimalPrecision;
parts = parseFloat(formattedValue).toFixed(precision).split(decimalSeparator);
} else {
parts = formattedValue.split(decimalSeparator);
}
beforeDecimal = parts[0];

@@ -168,3 +177,3 @@ afterDecimal = parts[1];

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

@@ -188,7 +197,2 @@

//check if there is no number before caret position
while(j > 0 && formattedValue[j]){
if(!formattedValue[j-1].match(numRegex)) j--;
else break;
}
return j;

@@ -199,5 +203,6 @@ }

e.persist();
const inputValue = e.target.value;
const el = e.target;
const inputValue = el.value;
const {formattedValue,value} = this.formatInput(inputValue);
let cursorPos = this.refs.input.selectionStart;
let cursorPos = el.selectionStart;

@@ -207,3 +212,7 @@ //change the state

cursorPos = this.getCursorPosition(inputValue, formattedValue, cursorPos );
this.setCaretPosition(cursorPos);
/*
setting caret position within timeout of 0ms is required for mobile chrome,
otherwise browser resets the caret position after we set it
*/
setTimeout(() => this.setCaretPosition(el, cursorPos), 0);
if(callback) callback(e,value);

@@ -221,2 +230,25 @@ });

}
onKeyDown(e) {
const el = e.target;
const {selectionStart, selectionEnd, value} = el;
const {decimalPrecision} = this.props;
const {key} = e;
const numRegex = this.getNumberRegex(false, decimalPrecision !== false);
//Handle backspace and delete against non numerical/decimal characters
if(selectionEnd - selectionStart === 0) {
if (key === 'Delete' && !numRegex.test(value[selectionStart])) {
e.preventDefault();
let nextCursorPosition = selectionStart;
while (!numRegex.test(value[nextCursorPosition]) && nextCursorPosition < value.length) nextCursorPosition++;
this.setCaretPosition(el, nextCursorPosition);
} else if (key === 'Backspace' && !numRegex.test(value[selectionStart - 1])) {
e.preventDefault();
let prevCursorPosition = selectionStart;
while (!numRegex.test(value[prevCursorPosition - 1]) && prevCursorPosition > 0) prevCursorPosition--;
this.setCaretPosition(el, prevCursorPosition);
}
}
if (this.props.onKeyDown) this.props.onKeyDown(e);
}
render() {

@@ -229,14 +261,26 @@ const props = Object.assign({}, this.props);

const inputProps = Object.assign({}, props, {
type:'tel',
value:this.state.value,
onInput:this.onChange,
onChange:this.onChange,
onKeyDown:this.onKeyDown,
})
if(this.props.displayType === 'text'){
if( this.props.displayType === 'text'){
return (<span {...props}>{this.state.value}</span>);
}
else if (this.props.customInput) {
const CustomInput = this.props.customInput;
return (
<CustomInput
{...inputProps}
/>
)
}
return (
<input
{...props}
type="tel"
value={this.state.value}
ref="input"
onInput={this.onChange}
onChange={this.onChange}
{...inputProps}
/>

@@ -243,0 +287,0 @@ )

@@ -182,2 +182,70 @@ import React from 'react';

});
it('should round to passed decimal precision', () => {
const component = ReactTestUtils.renderIntoDocument(<FormatNumberInput decimalPrecision={4}/>);
const input = ReactTestUtils.findRenderedDOMComponentWithTag(
component, 'input'
);
//case 1st - already exactly precision 4 should stay that way
input.value = "4111.1111";
ReactTestUtils.Simulate.change(input);
expect(input.value).toEqual("4111.1111");
//case 2nd - longer precision should round
input.value = "4111.11111";
ReactTestUtils.Simulate.change(input);
expect(input.value).toEqual("4111.1111");
//case 3rd - shorter precision adds 0
input.value = "4111.111";
ReactTestUtils.Simulate.change(input);
expect(input.value).toEqual("4111.1110");
//case 4th - no decimal should round with 4 zeros
input.value = "4111";
ReactTestUtils.Simulate.change(input);
expect(input.value).toEqual("4111.0000");
});
it('should not round by default', () => {
const component = ReactTestUtils.renderIntoDocument(<FormatNumberInput />);
const input = ReactTestUtils.findRenderedDOMComponentWithTag(
component, 'input'
);
//case 1st - no rounding with long decimal
input.value = "4111.111111";
ReactTestUtils.Simulate.change(input);
expect(input.value).toEqual("4111.111111");
//case 2nd - no rounding with whole numbers
input.value = "4111";
ReactTestUtils.Simulate.change(input);
expect(input.value).toEqual("4111");
//case 3rd - no rounding on single place decimals
input.value = "4111.1";
ReactTestUtils.Simulate.change(input);
expect(input.value).toEqual("4111.1");
});
it('should round default 2 places', () => {
const component = ReactTestUtils.renderIntoDocument(<FormatNumberInput decimalPrecision={true} />);
const input = ReactTestUtils.findRenderedDOMComponentWithTag(
component, 'input'
);
//case 1st - auto round to 2 places
input.value = "4111.1111";
ReactTestUtils.Simulate.change(input);
expect(input.value).toEqual("4111.11");
//case 2nd - auto round whole integers
input.value = "4111";
ReactTestUtils.Simulate.change(input);
expect(input.value).toEqual("4111.00");
});
});

@@ -226,2 +294,26 @@

});
it('should not round decimals by defualt', () => {
const component = ReactTestUtils.renderIntoDocument(<FormatNumberInput value="4111" displayType={'text'} />);
const span = ReactTestUtils.findRenderedDOMComponentWithTag(
component, 'span'
);
expect(span.textContent).toEqual("4111");
});
it('should round to 2 decimals if passed true', () => {
const component = ReactTestUtils.renderIntoDocument(<FormatNumberInput value="4111" displayType={'text'} decimalPrecision={true} />);
const span = ReactTestUtils.findRenderedDOMComponentWithTag(
component, 'span'
);
expect(span.textContent).toEqual("4111.00");
});
it('should round to 4 decimals if passed 4', () => {
const component = ReactTestUtils.renderIntoDocument(<FormatNumberInput value="4111.11" displayType={'text'} decimalPrecision={4} />);
const span = ReactTestUtils.findRenderedDOMComponentWithTag(
component, 'span'
);
expect(span.textContent).toEqual("4111.1100");
});
});

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

output: {
publicPath: "http://localhost:8080/",
publicPath: "http://localhost:9000/",
// path: path.join(__dirname, "public","js"),

@@ -13,0 +13,0 @@ filename: '[name].js'

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