react-number-format
Advanced tools
Comparing version 0.1.3 to 1.0.0
/*! | ||
* react-number-format - 0.1.3 | ||
* react-number-format - 1.0.0 | ||
* Author : Sudhanshu Yadav | ||
@@ -73,170 +73,284 @@ * Copyright (c) 2016 to Sudhanshu Yadav - ignitersworld.com , released under the MIT license. | ||
var React = __webpack_require__(2); | ||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
var NumberFormat = React.createClass({ | ||
displayName: 'NumberFormat', | ||
getInitialState: function getInitialState() { | ||
return { | ||
value: this.formatInput(this.props.value).formattedValue | ||
var _react = __webpack_require__(2); | ||
var _react2 = _interopRequireDefault(_react); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } | ||
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 escapeRegExp(str) { | ||
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); | ||
} | ||
var propTypes = { | ||
thousandSeparator: _react.PropTypes.oneOf([',', '.', true, false]), | ||
decimalSeperator: _react.PropTypes.oneOf([',', '.', true, false]), | ||
displayType: _react.PropTypes.oneOf(['input', 'text']), | ||
prefix: _react.PropTypes.string, | ||
suffix: _react.PropTypes.string, | ||
format: _react.PropTypes.oneOfType([_react.PropTypes.string, _react.PropTypes.func]), | ||
mask: _react.PropTypes.string, | ||
value: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]) | ||
}; | ||
var defaultProps = { | ||
displayType: 'input', | ||
decimalSeperator: '.' | ||
}; | ||
var NumberFormat = function (_React$Component) { | ||
_inherits(NumberFormat, _React$Component); | ||
function NumberFormat(props) { | ||
_classCallCheck(this, NumberFormat); | ||
var _this = _possibleConstructorReturn(this, (NumberFormat.__proto__ || Object.getPrototypeOf(NumberFormat)).call(this, props)); | ||
_this.state = { | ||
value: _this.formatInput(props.value).formattedValue | ||
}; | ||
}, | ||
getDefaultProps: function getDefaultProps() { | ||
return { | ||
displayType: 'input' | ||
}; | ||
}, | ||
componentWillReceiveProps: function componentWillReceiveProps(newProps) { | ||
this.setState({ | ||
value: this.formatInput(newProps.value).formattedValue | ||
}); | ||
}, | ||
setCaretPosition: function setCaretPosition(caretPos) { | ||
var 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) { | ||
var range = el.createTextRange(); | ||
range.move('character', caretPos); | ||
range.select(); | ||
return true; | ||
_this.onChange = _this.onChange.bind(_this); | ||
_this.onInput = _this.onInput.bind(_this); | ||
return _this; | ||
} | ||
_createClass(NumberFormat, [{ | ||
key: 'componentWillReceiveProps', | ||
value: function componentWillReceiveProps(newProps) { | ||
this.setState({ | ||
value: this.formatInput(newProps.value).formattedValue | ||
}); | ||
} | ||
}, { | ||
key: 'getSeperators', | ||
value: function getSeperators() { | ||
var _props = this.props; | ||
var thousandSeparator = _props.thousandSeparator; | ||
var decimalSeperator = _props.decimalSeperator; | ||
if (thousandSeparator === true) { | ||
thousandSeparator = ','; | ||
} | ||
// (el.selectionStart === 0 added for Firefox bug) | ||
if (el.selectionStart || el.selectionStart === 0) { | ||
el.focus(); | ||
el.setSelectionRange(caretPos, caretPos); | ||
return true; | ||
if (decimalSeperator && thousandSeparator) { | ||
decimalSeperator = thousandSeparator === ',' ? '.' : ','; | ||
} | ||
// fail city, fortunately this never happens (as far as I've tested) :) | ||
el.focus(); | ||
return false; | ||
if (decimalSeperator === true) { | ||
decimalSeperator = '.'; | ||
} | ||
return { | ||
decimalSeperator: decimalSeperator, | ||
thousandSeparator: thousandSeparator | ||
}; | ||
} | ||
}, | ||
formatWithPattern: function formatWithPattern(str) { | ||
var _props = this.props; | ||
var format = _props.format; | ||
var mask = _props.mask; | ||
}, { | ||
key: 'getNumberRegex', | ||
value: function getNumberRegex(g) { | ||
var _getSeperators = this.getSeperators(); | ||
if (!format) return str; | ||
var hashCount = format.split('#').length - 1; | ||
var hashIdx = 0; | ||
var frmtdStr = format; | ||
var decimalSeperator = _getSeperators.decimalSeperator; | ||
for (var i = 0, ln = str.length; i < ln; i++) { | ||
if (i < hashCount) { | ||
hashIdx = frmtdStr.indexOf('#'); | ||
frmtdStr = frmtdStr.replace('#', str[i]); | ||
return new RegExp('\\d' + (decimalSeperator ? '|' + escapeRegExp(decimalSeperator) : ''), g ? 'g' : undefined); | ||
} | ||
}, { | ||
key: 'setCaretPosition', | ||
value: function setCaretPosition(caretPos) { | ||
var 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) { | ||
var 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; | ||
} | ||
} | ||
}, { | ||
key: 'formatWithPattern', | ||
value: function formatWithPattern(str) { | ||
var _props2 = this.props; | ||
var format = _props2.format; | ||
var mask = _props2.mask; | ||
var lastIdx = frmtdStr.lastIndexOf('#'); | ||
if (!format) return str; | ||
var hashCount = format.split('#').length - 1; | ||
var hashIdx = 0; | ||
var frmtdStr = format; | ||
if (mask) { | ||
return frmtdStr.replace(/#/g, mask); | ||
for (var i = 0, ln = str.length; i < ln; i++) { | ||
if (i < hashCount) { | ||
hashIdx = frmtdStr.indexOf('#'); | ||
frmtdStr = frmtdStr.replace('#', str[i]); | ||
} | ||
} | ||
var lastIdx = frmtdStr.lastIndexOf('#'); | ||
if (mask) { | ||
return frmtdStr.replace(/#/g, mask); | ||
} | ||
return frmtdStr.substring(0, hashIdx + 1) + (lastIdx !== -1 ? frmtdStr.substring(lastIdx + 1, frmtdStr.length) : ''); | ||
} | ||
return frmtdStr.substring(0, hashIdx + 1) + (lastIdx !== -1 ? frmtdStr.substring(lastIdx + 1, frmtdStr.length) : ''); | ||
}, | ||
formatInput: function formatInput(val) { | ||
var _props2 = this.props; | ||
var prefix = _props2.prefix; | ||
var thousandSeparator = _props2.thousandSeparator; | ||
var suffix = _props2.suffix; | ||
var mask = _props2.mask; | ||
var format = _props2.format; | ||
}, { | ||
key: 'formatInput', | ||
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 maskPattern = format && typeof format == "string" && !!mask; | ||
var _getSeperators2 = this.getSeperators(); | ||
if (!val || !(val + "").match(/\d/g)) return { value: "", formattedValue: maskPattern ? "" : "" }; | ||
var num = (val + "").match(/\d/g).join(""); | ||
var thousandSeparator = _getSeperators2.thousandSeparator; | ||
var decimalSeperator = _getSeperators2.decimalSeperator; | ||
var formattedValue = num; | ||
var maskPattern = format && typeof format == 'string' && !!mask; | ||
if (format) { | ||
if (typeof format == 'string') { | ||
formattedValue = this.formatWithPattern(formattedValue); | ||
} else if (typeof format == "function") { | ||
formattedValue = format(formattedValue); | ||
var numRegex = this.getNumberRegex(true); | ||
if (!val || !(val + '').match(numRegex)) return { value: '', formattedValue: maskPattern ? '' : '' }; | ||
var num = (val + '').match(numRegex).join(''); | ||
var formattedValue = num; | ||
if (format) { | ||
if (typeof format == 'string') { | ||
formattedValue = this.formatWithPattern(formattedValue); | ||
} else if (typeof format == 'function') { | ||
formattedValue = format(formattedValue); | ||
} | ||
} else { | ||
var beforeDecimal = formattedValue, | ||
afterDecimal = ''; | ||
var hasDecimals = formattedValue.indexOf(decimalSeperator) !== -1; | ||
if (decimalSeperator && hasDecimals) { | ||
var parts = formattedValue.split(decimalSeperator); | ||
beforeDecimal = parts[0]; | ||
afterDecimal = parts[1]; | ||
} | ||
if (thousandSeparator) { | ||
beforeDecimal = beforeDecimal.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + thousandSeparator); | ||
} | ||
//add prefix and suffix | ||
if (prefix) beforeDecimal = prefix + beforeDecimal; | ||
if (suffix) afterDecimal = afterDecimal + suffix; | ||
formattedValue = beforeDecimal + (hasDecimals && decimalSeperator || '') + afterDecimal; | ||
} | ||
} else { | ||
if (thousandSeparator) formattedValue = formattedValue.replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,"); | ||
//add prefix and suffix | ||
if (prefix) formattedValue = prefix + formattedValue; | ||
if (suffix) formattedValue = formattedValue + suffix; | ||
return { | ||
value: formattedValue.match(numRegex).join(''), | ||
formattedValue: formattedValue | ||
}; | ||
} | ||
}, { | ||
key: 'getCursorPosition', | ||
value: function getCursorPosition(inputValue, formattedValue, cursorPos) { | ||
var numRegex = this.getNumberRegex(); | ||
return { | ||
value: formattedValue.match(/\d/g).join(""), | ||
formattedValue: formattedValue | ||
}; | ||
}, | ||
getCursorPosition: function getCursorPosition(inputValue, formattedValue, cursorPos) { | ||
var j = 0; | ||
for (var i = 0; i < cursorPos; i++) { | ||
if (!inputValue[i].match(/\d/) && inputValue[i] !== formattedValue[j]) continue; | ||
while (inputValue[i] !== formattedValue[j] && j < formattedValue.length) { | ||
j++; | ||
}j++; | ||
} | ||
var j = 0; | ||
for (var i = 0; i < cursorPos; i++) { | ||
if (!inputValue[i].match(numRegex) && inputValue[i] !== formattedValue[j]) continue; | ||
while (inputValue[i] !== formattedValue[j] && j < formattedValue.length) { | ||
j++; | ||
}j++; | ||
} | ||
//check if there is no number before caret position | ||
while (j > 0 && formattedValue[j]) { | ||
if (!formattedValue[j - 1].match(/\d/)) j--;else break; | ||
//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; | ||
} | ||
return j; | ||
}, | ||
onChangeHandler: function onChangeHandler(e, callback) { | ||
var _this = this; | ||
}, { | ||
key: 'onChangeHandler', | ||
value: function onChangeHandler(e, callback) { | ||
var _this2 = this; | ||
var inputValue = e.target.value; | ||
e.persist(); | ||
var inputValue = e.target.value + ''; | ||
var _formatInput = this.formatInput(inputValue); | ||
var _formatInput = this.formatInput(inputValue); | ||
var formattedValue = _formatInput.formattedValue; | ||
var value = _formatInput.value; | ||
var formattedValue = _formatInput.formattedValue; | ||
var value = _formatInput.value; | ||
var cursorPos = this.refs.input.selectionStart; | ||
var cursorPos = this.refs.input.selectionStart; | ||
//change the state | ||
this.setState({ value: formattedValue }, function () { | ||
cursorPos = _this.getCursorPosition(inputValue, formattedValue, cursorPos); | ||
_this.setCaretPosition(cursorPos); | ||
if (callback) callback(e, value); | ||
}); | ||
//change the state | ||
this.setState({ value: formattedValue }, function () { | ||
cursorPos = _this2.getCursorPosition(inputValue, formattedValue, cursorPos); | ||
_this2.setCaretPosition(cursorPos); | ||
if (callback) callback(e, value); | ||
}); | ||
return value; | ||
}, | ||
onChange: function onChange(e) { | ||
this.onChangeHandler(e, this.props.onChange); | ||
}, | ||
onInput: function onInput(e) { | ||
this.onChangeHandler(e, this.props.onInput); | ||
}, | ||
render: function render() { | ||
var props = _extends({}, this.props); | ||
return value; | ||
} | ||
}, { | ||
key: 'onChange', | ||
value: function onChange(e) { | ||
this.onChangeHandler(e, this.props.onChange); | ||
} | ||
}, { | ||
key: 'onInput', | ||
value: function onInput(e) { | ||
this.onChangeHandler(e, this.props.onInput); | ||
} | ||
}, { | ||
key: 'render', | ||
value: function render() { | ||
var props = _extends({}, this.props); | ||
['thousandSeparator', 'displayType', 'prefix', 'suffix', 'format', 'mask', 'value'].forEach(function (key) { | ||
delete props[key]; | ||
}); | ||
Object.keys(propTypes).forEach(function (key) { | ||
delete props[key]; | ||
}); | ||
if (this.props.displayType === "text") { | ||
return React.createElement( | ||
'span', | ||
props, | ||
this.state.value | ||
); | ||
if (this.props.displayType === 'text') { | ||
return _react2.default.createElement( | ||
'span', | ||
props, | ||
this.state.value | ||
); | ||
} | ||
return _react2.default.createElement('input', _extends({}, props, { | ||
type: 'tel', | ||
value: this.state.value, | ||
ref: 'input', | ||
onInput: this.onChange, | ||
onChange: this.onChange | ||
})); | ||
} | ||
return React.createElement('input', _extends({}, props, { | ||
type: 'tel', | ||
value: this.state.value, | ||
ref: 'input', | ||
onInput: this.onChange, | ||
onChange: this.onChange | ||
})); | ||
} | ||
}); | ||
}]); | ||
return NumberFormat; | ||
}(_react2.default.Component); | ||
NumberFormat.propTypes = propTypes; | ||
NumberFormat.defaultProps = defaultProps; | ||
module.exports = NumberFormat; | ||
@@ -243,0 +357,0 @@ |
/*! | ||
* react-number-format - 0.1.3 | ||
* react-number-format - 1.0.0 | ||
* Author : Sudhanshu Yadav | ||
* Copyright (c) 2016 to Sudhanshu Yadav - ignitersworld.com , released under the MIT license. | ||
*/ | ||
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("react")):"function"==typeof define&&define.amd?define(["react"],e):"object"==typeof exports?exports.NumberFormat=e(require("react")):t.NumberFormat=e(t.React)}(this,function(t){return function(t){function e(n){if(r[n])return r[n].exports;var a=r[n]={exports:{},id:n,loaded:!1};return t[n].call(a.exports,a,a.exports,e),a.loaded=!0,a.exports}var r={};return e.m=t,e.c=r,e.p="",e(0)}([function(t,e,r){t.exports=r(1)},function(t,e,r){"use strict";var n=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(t[n]=r[n])}return t},a=r(2),o=a.createClass({displayName:"NumberFormat",getInitialState:function(){return{value:this.formatInput(this.props.value).formattedValue}},getDefaultProps:function(){return{displayType:"input"}},componentWillReceiveProps:function(t){this.setState({value:this.formatInput(t.value).formattedValue})},setCaretPosition:function(t){var e=this.refs.input;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)}},formatWithPattern:function(t){var e=this.props,r=e.format,n=e.mask;if(!r)return t;for(var a=r.split("#").length-1,o=0,i=r,s=0,u=t.length;s<u;s++)s<a&&(o=i.indexOf("#"),i=i.replace("#",t[s]));var f=i.lastIndexOf("#");return n?i.replace(/#/g,n):i.substring(0,o+1)+(f!==-1?i.substring(f+1,i.length):"")},formatInput:function(t){var e=this.props,r=e.prefix,n=e.thousandSeparator,a=e.suffix,o=(e.mask,e.format);if(!t||!(t+"").match(/\d/g))return{value:"",formattedValue:""};var i=(t+"").match(/\d/g).join(""),s=i;return o?"string"==typeof o?s=this.formatWithPattern(s):"function"==typeof o&&(s=o(s)):(n&&(s=s.replace(/(\d)(?=(\d{3})+(?!\d))/g,"$1,")),r&&(s=r+s),a&&(s+=a)),{value:s.match(/\d/g).join(""),formattedValue:s}},getCursorPosition:function(t,e,r){for(var n=0,a=0;a<r;a++)if(t[a].match(/\d/)||t[a]===e[n]){for(;t[a]!==e[n]&&n<e.length;)n++;n++}for(;n>0&&e[n]&&!e[n-1].match(/\d/);)n--;return n},onChangeHandler:function(t,e){var r=this,n=t.target.value,a=this.formatInput(n),o=a.formattedValue,i=a.value,s=this.refs.input.selectionStart;return this.setState({value:o},function(){s=r.getCursorPosition(n,o,s),r.setCaretPosition(s),e&&e(t,i)}),i},onChange:function(t){this.onChangeHandler(t,this.props.onChange)},onInput:function(t){this.onChangeHandler(t,this.props.onInput)},render:function(){var t=n({},this.props);return["thousandSeparator","displayType","prefix","suffix","format","mask","value"].forEach(function(e){delete t[e]}),"text"===this.props.displayType?a.createElement("span",t,this.state.value):a.createElement("input",n({},t,{type:"tel",value:this.state.value,ref:"input",onInput:this.onChange,onChange:this.onChange}))}});t.exports=o},function(e,r){e.exports=t}])}); | ||
!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]),decimalSeperator: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",decimalSeperator:"."},y=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){this.setState({value:this.formatInput(e.value).formattedValue})}},{key:"getSeperators",value:function(){var e=this.props,t=e.thousandSeparator,r=e.decimalSeperator;return t===!0&&(t=","),r&&t&&(r=","===t?".":","),r===!0&&(r="."),{decimalSeperator:r,thousandSeparator:t}}},{key:"getNumberRegex",value:function(e){var t=this.getSeperators(),r=t.decimalSeperator;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.getSeperators(),i=a.thousandSeparator,u=a.decimalSeperator,s=this.getNumberRegex(!0);if(!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 y=f.split(u);l=y[0],c=y[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);y.propTypes=c,y.defaultProps=h,e.exports=y},function(t,r){t.exports=e}])}); |
@@ -1,10 +0,13 @@ | ||
const React = require('react'); | ||
const ReactDOM = require('react-dom'); | ||
const NumberFormat = require('../../src/number_format'); | ||
import React from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
import NumberFormat from '../../src/number_format'; | ||
const App = React.createClass({ | ||
getInitialState : function(){ | ||
return {}; | ||
}, | ||
formatExpiryChange: function(val){ | ||
class App extends React.Component { | ||
constructor() { | ||
super(); | ||
this.state = {}; | ||
this.formatExpiryChange = this.formatExpiryChange.bind(this); | ||
} | ||
formatExpiryChange(val) { | ||
if(val && Number(val[0]) > 1){ | ||
@@ -18,4 +21,5 @@ val = '0'+val; | ||
return val; | ||
}, | ||
render : function(){ | ||
} | ||
render() { | ||
return ( | ||
@@ -46,2 +50,9 @@ <div> | ||
<h3> | ||
Custom thousand seperator : Format currency in input | ||
</h3> | ||
<NumberFormat thousandSeparator={'.'} decimalSeperator={','} prefix={'$'} /> | ||
</div> | ||
<div className="example"> | ||
<h3> | ||
Format with pattern : Format credit card in an input | ||
@@ -68,4 +79,5 @@ </h3> | ||
} | ||
}); | ||
} | ||
ReactDOM.render(<App />, document.getElementById('app')); |
@@ -5,170 +5,284 @@ 'use strict'; | ||
var React = require('react'); | ||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
var NumberFormat = React.createClass({ | ||
displayName: 'NumberFormat', | ||
getInitialState: function getInitialState() { | ||
return { | ||
value: this.formatInput(this.props.value).formattedValue | ||
var _react = require('react'); | ||
var _react2 = _interopRequireDefault(_react); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } | ||
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 escapeRegExp(str) { | ||
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); | ||
} | ||
var propTypes = { | ||
thousandSeparator: _react.PropTypes.oneOf([',', '.', true, false]), | ||
decimalSeperator: _react.PropTypes.oneOf([',', '.', true, false]), | ||
displayType: _react.PropTypes.oneOf(['input', 'text']), | ||
prefix: _react.PropTypes.string, | ||
suffix: _react.PropTypes.string, | ||
format: _react.PropTypes.oneOfType([_react.PropTypes.string, _react.PropTypes.func]), | ||
mask: _react.PropTypes.string, | ||
value: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]) | ||
}; | ||
var defaultProps = { | ||
displayType: 'input', | ||
decimalSeperator: '.' | ||
}; | ||
var NumberFormat = function (_React$Component) { | ||
_inherits(NumberFormat, _React$Component); | ||
function NumberFormat(props) { | ||
_classCallCheck(this, NumberFormat); | ||
var _this = _possibleConstructorReturn(this, (NumberFormat.__proto__ || Object.getPrototypeOf(NumberFormat)).call(this, props)); | ||
_this.state = { | ||
value: _this.formatInput(props.value).formattedValue | ||
}; | ||
}, | ||
getDefaultProps: function getDefaultProps() { | ||
return { | ||
displayType: 'input' | ||
}; | ||
}, | ||
componentWillReceiveProps: function componentWillReceiveProps(newProps) { | ||
this.setState({ | ||
value: this.formatInput(newProps.value).formattedValue | ||
}); | ||
}, | ||
setCaretPosition: function setCaretPosition(caretPos) { | ||
var 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) { | ||
var range = el.createTextRange(); | ||
range.move('character', caretPos); | ||
range.select(); | ||
return true; | ||
_this.onChange = _this.onChange.bind(_this); | ||
_this.onInput = _this.onInput.bind(_this); | ||
return _this; | ||
} | ||
_createClass(NumberFormat, [{ | ||
key: 'componentWillReceiveProps', | ||
value: function componentWillReceiveProps(newProps) { | ||
this.setState({ | ||
value: this.formatInput(newProps.value).formattedValue | ||
}); | ||
} | ||
}, { | ||
key: 'getSeperators', | ||
value: function getSeperators() { | ||
var _props = this.props; | ||
var thousandSeparator = _props.thousandSeparator; | ||
var decimalSeperator = _props.decimalSeperator; | ||
if (thousandSeparator === true) { | ||
thousandSeparator = ','; | ||
} | ||
// (el.selectionStart === 0 added for Firefox bug) | ||
if (el.selectionStart || el.selectionStart === 0) { | ||
el.focus(); | ||
el.setSelectionRange(caretPos, caretPos); | ||
return true; | ||
if (decimalSeperator && thousandSeparator) { | ||
decimalSeperator = thousandSeparator === ',' ? '.' : ','; | ||
} | ||
// fail city, fortunately this never happens (as far as I've tested) :) | ||
el.focus(); | ||
return false; | ||
if (decimalSeperator === true) { | ||
decimalSeperator = '.'; | ||
} | ||
return { | ||
decimalSeperator: decimalSeperator, | ||
thousandSeparator: thousandSeparator | ||
}; | ||
} | ||
}, | ||
formatWithPattern: function formatWithPattern(str) { | ||
var _props = this.props; | ||
var format = _props.format; | ||
var mask = _props.mask; | ||
}, { | ||
key: 'getNumberRegex', | ||
value: function getNumberRegex(g) { | ||
var _getSeperators = this.getSeperators(); | ||
if (!format) return str; | ||
var hashCount = format.split('#').length - 1; | ||
var hashIdx = 0; | ||
var frmtdStr = format; | ||
var decimalSeperator = _getSeperators.decimalSeperator; | ||
for (var i = 0, ln = str.length; i < ln; i++) { | ||
if (i < hashCount) { | ||
hashIdx = frmtdStr.indexOf('#'); | ||
frmtdStr = frmtdStr.replace('#', str[i]); | ||
return new RegExp('\\d' + (decimalSeperator ? '|' + escapeRegExp(decimalSeperator) : ''), g ? 'g' : undefined); | ||
} | ||
}, { | ||
key: 'setCaretPosition', | ||
value: function setCaretPosition(caretPos) { | ||
var 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) { | ||
var 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; | ||
} | ||
} | ||
}, { | ||
key: 'formatWithPattern', | ||
value: function formatWithPattern(str) { | ||
var _props2 = this.props; | ||
var format = _props2.format; | ||
var mask = _props2.mask; | ||
var lastIdx = frmtdStr.lastIndexOf('#'); | ||
if (!format) return str; | ||
var hashCount = format.split('#').length - 1; | ||
var hashIdx = 0; | ||
var frmtdStr = format; | ||
if (mask) { | ||
return frmtdStr.replace(/#/g, mask); | ||
for (var i = 0, ln = str.length; i < ln; i++) { | ||
if (i < hashCount) { | ||
hashIdx = frmtdStr.indexOf('#'); | ||
frmtdStr = frmtdStr.replace('#', str[i]); | ||
} | ||
} | ||
var lastIdx = frmtdStr.lastIndexOf('#'); | ||
if (mask) { | ||
return frmtdStr.replace(/#/g, mask); | ||
} | ||
return frmtdStr.substring(0, hashIdx + 1) + (lastIdx !== -1 ? frmtdStr.substring(lastIdx + 1, frmtdStr.length) : ''); | ||
} | ||
return frmtdStr.substring(0, hashIdx + 1) + (lastIdx !== -1 ? frmtdStr.substring(lastIdx + 1, frmtdStr.length) : ''); | ||
}, | ||
formatInput: function formatInput(val) { | ||
var _props2 = this.props; | ||
var prefix = _props2.prefix; | ||
var thousandSeparator = _props2.thousandSeparator; | ||
var suffix = _props2.suffix; | ||
var mask = _props2.mask; | ||
var format = _props2.format; | ||
}, { | ||
key: 'formatInput', | ||
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 maskPattern = format && typeof format == "string" && !!mask; | ||
var _getSeperators2 = this.getSeperators(); | ||
if (!val || !(val + "").match(/\d/g)) return { value: "", formattedValue: maskPattern ? "" : "" }; | ||
var num = (val + "").match(/\d/g).join(""); | ||
var thousandSeparator = _getSeperators2.thousandSeparator; | ||
var decimalSeperator = _getSeperators2.decimalSeperator; | ||
var formattedValue = num; | ||
var maskPattern = format && typeof format == 'string' && !!mask; | ||
if (format) { | ||
if (typeof format == 'string') { | ||
formattedValue = this.formatWithPattern(formattedValue); | ||
} else if (typeof format == "function") { | ||
formattedValue = format(formattedValue); | ||
var numRegex = this.getNumberRegex(true); | ||
if (!val || !(val + '').match(numRegex)) return { value: '', formattedValue: maskPattern ? '' : '' }; | ||
var num = (val + '').match(numRegex).join(''); | ||
var formattedValue = num; | ||
if (format) { | ||
if (typeof format == 'string') { | ||
formattedValue = this.formatWithPattern(formattedValue); | ||
} else if (typeof format == 'function') { | ||
formattedValue = format(formattedValue); | ||
} | ||
} else { | ||
var beforeDecimal = formattedValue, | ||
afterDecimal = ''; | ||
var hasDecimals = formattedValue.indexOf(decimalSeperator) !== -1; | ||
if (decimalSeperator && hasDecimals) { | ||
var parts = formattedValue.split(decimalSeperator); | ||
beforeDecimal = parts[0]; | ||
afterDecimal = parts[1]; | ||
} | ||
if (thousandSeparator) { | ||
beforeDecimal = beforeDecimal.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + thousandSeparator); | ||
} | ||
//add prefix and suffix | ||
if (prefix) beforeDecimal = prefix + beforeDecimal; | ||
if (suffix) afterDecimal = afterDecimal + suffix; | ||
formattedValue = beforeDecimal + (hasDecimals && decimalSeperator || '') + afterDecimal; | ||
} | ||
} else { | ||
if (thousandSeparator) formattedValue = formattedValue.replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,"); | ||
//add prefix and suffix | ||
if (prefix) formattedValue = prefix + formattedValue; | ||
if (suffix) formattedValue = formattedValue + suffix; | ||
return { | ||
value: formattedValue.match(numRegex).join(''), | ||
formattedValue: formattedValue | ||
}; | ||
} | ||
}, { | ||
key: 'getCursorPosition', | ||
value: function getCursorPosition(inputValue, formattedValue, cursorPos) { | ||
var numRegex = this.getNumberRegex(); | ||
return { | ||
value: formattedValue.match(/\d/g).join(""), | ||
formattedValue: formattedValue | ||
}; | ||
}, | ||
getCursorPosition: function getCursorPosition(inputValue, formattedValue, cursorPos) { | ||
var j = 0; | ||
for (var i = 0; i < cursorPos; i++) { | ||
if (!inputValue[i].match(/\d/) && inputValue[i] !== formattedValue[j]) continue; | ||
while (inputValue[i] !== formattedValue[j] && j < formattedValue.length) { | ||
j++; | ||
}j++; | ||
} | ||
var j = 0; | ||
for (var i = 0; i < cursorPos; i++) { | ||
if (!inputValue[i].match(numRegex) && inputValue[i] !== formattedValue[j]) continue; | ||
while (inputValue[i] !== formattedValue[j] && j < formattedValue.length) { | ||
j++; | ||
}j++; | ||
} | ||
//check if there is no number before caret position | ||
while (j > 0 && formattedValue[j]) { | ||
if (!formattedValue[j - 1].match(/\d/)) j--;else break; | ||
//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; | ||
} | ||
return j; | ||
}, | ||
onChangeHandler: function onChangeHandler(e, callback) { | ||
var _this = this; | ||
}, { | ||
key: 'onChangeHandler', | ||
value: function onChangeHandler(e, callback) { | ||
var _this2 = this; | ||
var inputValue = e.target.value; | ||
e.persist(); | ||
var inputValue = e.target.value + ''; | ||
var _formatInput = this.formatInput(inputValue); | ||
var _formatInput = this.formatInput(inputValue); | ||
var formattedValue = _formatInput.formattedValue; | ||
var value = _formatInput.value; | ||
var formattedValue = _formatInput.formattedValue; | ||
var value = _formatInput.value; | ||
var cursorPos = this.refs.input.selectionStart; | ||
var cursorPos = this.refs.input.selectionStart; | ||
//change the state | ||
this.setState({ value: formattedValue }, function () { | ||
cursorPos = _this.getCursorPosition(inputValue, formattedValue, cursorPos); | ||
_this.setCaretPosition(cursorPos); | ||
if (callback) callback(e, value); | ||
}); | ||
//change the state | ||
this.setState({ value: formattedValue }, function () { | ||
cursorPos = _this2.getCursorPosition(inputValue, formattedValue, cursorPos); | ||
_this2.setCaretPosition(cursorPos); | ||
if (callback) callback(e, value); | ||
}); | ||
return value; | ||
}, | ||
onChange: function onChange(e) { | ||
this.onChangeHandler(e, this.props.onChange); | ||
}, | ||
onInput: function onInput(e) { | ||
this.onChangeHandler(e, this.props.onInput); | ||
}, | ||
render: function render() { | ||
var props = _extends({}, this.props); | ||
return value; | ||
} | ||
}, { | ||
key: 'onChange', | ||
value: function onChange(e) { | ||
this.onChangeHandler(e, this.props.onChange); | ||
} | ||
}, { | ||
key: 'onInput', | ||
value: function onInput(e) { | ||
this.onChangeHandler(e, this.props.onInput); | ||
} | ||
}, { | ||
key: 'render', | ||
value: function render() { | ||
var props = _extends({}, this.props); | ||
['thousandSeparator', 'displayType', 'prefix', 'suffix', 'format', 'mask', 'value'].forEach(function (key) { | ||
delete props[key]; | ||
}); | ||
Object.keys(propTypes).forEach(function (key) { | ||
delete props[key]; | ||
}); | ||
if (this.props.displayType === "text") { | ||
return React.createElement( | ||
'span', | ||
props, | ||
this.state.value | ||
); | ||
if (this.props.displayType === 'text') { | ||
return _react2.default.createElement( | ||
'span', | ||
props, | ||
this.state.value | ||
); | ||
} | ||
return _react2.default.createElement('input', _extends({}, props, { | ||
type: 'tel', | ||
value: this.state.value, | ||
ref: 'input', | ||
onInput: this.onChange, | ||
onChange: this.onChange | ||
})); | ||
} | ||
return React.createElement('input', _extends({}, props, { | ||
type: 'tel', | ||
value: this.state.value, | ||
ref: 'input', | ||
onInput: this.onChange, | ||
onChange: this.onChange | ||
})); | ||
} | ||
}); | ||
}]); | ||
return NumberFormat; | ||
}(_react2.default.Component); | ||
NumberFormat.propTypes = propTypes; | ||
NumberFormat.defaultProps = defaultProps; | ||
module.exports = NumberFormat; |
{ | ||
"name": "react-number-format", | ||
"description": "React component to format number in an input or as a text.", | ||
"version": "0.1.3", | ||
"version": "1.0.0", | ||
"main": "lib/number_format.js", | ||
@@ -6,0 +6,0 @@ "author": "Sudhanshu Yadav", |
@@ -20,3 +20,4 @@ # react-number-format | ||
| ------------- |-------------| -----| -------- | | ||
| thousandSeparator | Boolean: true/false | false | Add thousand separators on number | | ||
| thousandSeparator | mixed: true/false (boolean) or ,/. (string) | false | Add thousand separators on number | | ||
| decimalSeperator | mixed: ./, (string) or true/false (boolean)| . | Suppor decimal point on a number | | ||
| prefix | String (ex : $) | none | Add a prefix before the number | | ||
@@ -82,2 +83,10 @@ | suffix | String (ex : /-) | none | Add a prefix after the number | | ||
### Major Updates | ||
### v1.0.0 | ||
- Support decimals | ||
- Support changing thousandSeparator to ',' | ||
- Updated complete code to ES6 | ||
- Added propTypes validation | ||
- Fixed #1, #7, #8, #9 | ||
### Development | ||
@@ -84,0 +93,0 @@ - Download the zip |
@@ -1,21 +0,72 @@ | ||
const React = require('react'); | ||
//const React = require('react'); | ||
import React, {PropTypes} from 'react'; | ||
const NumberFormat = React.createClass({ | ||
displayName : 'NumberFormat', | ||
getInitialState : function(){ | ||
return { | ||
value : this.formatInput(this.props.value).formattedValue | ||
function escapeRegExp(str) { | ||
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); | ||
} | ||
const propTypes = { | ||
thousandSeparator: PropTypes.oneOf([',', '.', true, false]), | ||
decimalSeperator: PropTypes.oneOf([',', '.', true, false]), | ||
displayType: PropTypes.oneOf(['input', 'text']), | ||
prefix: PropTypes.string, | ||
suffix: PropTypes.string, | ||
format: PropTypes.oneOfType([ | ||
PropTypes.string, | ||
PropTypes.func | ||
]), | ||
mask: PropTypes.string, | ||
value: PropTypes.oneOfType([ | ||
PropTypes.number, | ||
PropTypes.string | ||
]) | ||
}; | ||
const defaultProps = { | ||
displayType: 'input', | ||
decimalSeperator: '.' | ||
}; | ||
class NumberFormat extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
this.state = { | ||
value: this.formatInput(props.value).formattedValue | ||
} | ||
}, | ||
getDefaultProps : function(){ | ||
return { | ||
displayType : 'input' | ||
} | ||
}, | ||
componentWillReceiveProps: function(newProps){ | ||
this.onChange = this.onChange.bind(this); | ||
this.onInput = this.onInput.bind(this); | ||
} | ||
componentWillReceiveProps(newProps) { | ||
this.setState({ | ||
value : this.formatInput(newProps.value).formattedValue | ||
}); | ||
}, | ||
setCaretPosition : function(caretPos) { | ||
} | ||
getSeperators() { | ||
let {thousandSeparator, decimalSeperator} = this.props; | ||
if (thousandSeparator === true) { | ||
thousandSeparator = ',' | ||
} | ||
if (decimalSeperator && thousandSeparator) { | ||
decimalSeperator = thousandSeparator === ',' ? '.' : ','; | ||
} | ||
if (decimalSeperator === true) { | ||
decimalSeperator = '.' | ||
} | ||
return { | ||
decimalSeperator, | ||
thousandSeparator | ||
} | ||
} | ||
getNumberRegex(g) { | ||
const {decimalSeperator} = this.getSeperators(); | ||
return new RegExp('\\d' + (decimalSeperator ? '|' + escapeRegExp(decimalSeperator) : ''), g ? 'g' : undefined); | ||
} | ||
setCaretPosition(caretPos) { | ||
const el = this.refs.input; | ||
@@ -45,4 +96,5 @@ el.value = el.value; | ||
} | ||
}, | ||
formatWithPattern : function(str){ | ||
} | ||
formatWithPattern(str) { | ||
const {format,mask} = this.props; | ||
@@ -67,10 +119,14 @@ if (!format) return str; | ||
return frmtdStr.substring(0,hashIdx + 1) + (lastIdx!==-1 ? frmtdStr.substring(lastIdx + 1, frmtdStr.length) :''); | ||
}, | ||
formatInput : function(val){ | ||
const {prefix, thousandSeparator, suffix, mask,format} = this.props; | ||
const maskPattern = format && typeof format == "string" && !!mask; | ||
} | ||
if(!val || !((val+"").match(/\d/g))) return {value :"", formattedValue: (maskPattern ? "" : "")} | ||
const num = (val+"").match(/\d/g).join(""); | ||
formatInput(val) { | ||
const {prefix, suffix, mask, format} = this.props; | ||
const {thousandSeparator, decimalSeperator} = this.getSeperators() | ||
const maskPattern = format && typeof format == 'string' && !!mask; | ||
const numRegex = this.getNumberRegex(true); | ||
if(!val || !((val+'').match(numRegex))) return {value :'', formattedValue: (maskPattern ? '' : '')} | ||
const num = (val+'').match(numRegex).join(''); | ||
let formattedValue = num; | ||
@@ -82,3 +138,3 @@ | ||
} | ||
else if(typeof format == "function"){ | ||
else if(typeof format == 'function'){ | ||
formattedValue = format(formattedValue); | ||
@@ -88,18 +144,31 @@ } | ||
else{ | ||
if(thousandSeparator) formattedValue = formattedValue.replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,"); | ||
let beforeDecimal = formattedValue, afterDecimal = ''; | ||
const hasDecimals = formattedValue.indexOf(decimalSeperator) !== -1; | ||
if(decimalSeperator && hasDecimals) { | ||
const parts = formattedValue.split(decimalSeperator) | ||
beforeDecimal = parts[0]; | ||
afterDecimal = parts[1]; | ||
} | ||
if(thousandSeparator) { | ||
beforeDecimal = beforeDecimal.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + thousandSeparator); | ||
} | ||
//add prefix and suffix | ||
if(prefix) beforeDecimal = prefix + beforeDecimal; | ||
if(suffix) afterDecimal = afterDecimal + suffix; | ||
//add prefix and suffix | ||
if(prefix) formattedValue = prefix + formattedValue; | ||
if(suffix) formattedValue = formattedValue + suffix; | ||
formattedValue = beforeDecimal + (hasDecimals && decimalSeperator || '') + afterDecimal; | ||
} | ||
return { | ||
value : formattedValue.match(/\d/g).join(""), | ||
value : formattedValue.match(numRegex).join(''), | ||
formattedValue : formattedValue | ||
} | ||
}, | ||
getCursorPosition : function(inputValue,formattedValue,cursorPos){ | ||
} | ||
getCursorPosition(inputValue, formattedValue, cursorPos) { | ||
const numRegex = this.getNumberRegex(); | ||
let j=0; | ||
for(let i=0; i<cursorPos; i++){ | ||
if(!inputValue[i].match(/\d/) && inputValue[i] !== formattedValue[j]) continue; | ||
if(!inputValue[i].match(numRegex) && inputValue[i] !== formattedValue[j]) continue; | ||
while(inputValue[i] !== formattedValue[j] && j<formattedValue.length) j++; | ||
@@ -111,9 +180,11 @@ j++; | ||
while(j > 0 && formattedValue[j]){ | ||
if(!formattedValue[j-1].match(/\d/)) j--; | ||
if(!formattedValue[j-1].match(numRegex)) j--; | ||
else break; | ||
} | ||
return j; | ||
}, | ||
onChangeHandler : function(e,callback){ | ||
const inputValue = e.target.value; | ||
} | ||
onChangeHandler(e,callback) { | ||
e.persist(); | ||
const inputValue = e.target.value + ''; | ||
const {formattedValue,value} = this.formatInput(inputValue); | ||
@@ -124,3 +195,3 @@ let cursorPos = this.refs.input.selectionStart; | ||
this.setState({value : formattedValue},()=>{ | ||
cursorPos = this.getCursorPosition(inputValue, formattedValue,cursorPos ); | ||
cursorPos = this.getCursorPosition(inputValue, formattedValue, cursorPos ); | ||
this.setCaretPosition(cursorPos); | ||
@@ -131,13 +202,14 @@ if(callback) callback(e,value); | ||
return value; | ||
}, | ||
onChange : function(e){ | ||
} | ||
onChange(e) { | ||
this.onChangeHandler(e,this.props.onChange); | ||
}, | ||
onInput : function(e){ | ||
} | ||
onInput(e) { | ||
this.onChangeHandler(e,this.props.onInput); | ||
}, | ||
render : function(){ | ||
} | ||
render() { | ||
const props = Object.assign({}, this.props); | ||
['thousandSeparator', 'displayType', 'prefix', 'suffix', 'format', 'mask', 'value'].forEach((key) => { | ||
Object.keys(propTypes).forEach((key) => { | ||
delete props[key]; | ||
@@ -147,3 +219,3 @@ }); | ||
if(this.props.displayType === "text"){ | ||
if(this.props.displayType === 'text'){ | ||
return (<span {...props}>{this.state.value}</span>); | ||
@@ -154,3 +226,3 @@ } | ||
{...props} | ||
type='tel' | ||
type="tel" | ||
value={this.state.value} | ||
@@ -163,4 +235,7 @@ ref="input" | ||
} | ||
}); | ||
} | ||
module.exports = NumberFormat; | ||
NumberFormat.propTypes = propTypes; | ||
NumberFormat.defaultProps = defaultProps; | ||
module.exports = NumberFormat; |
@@ -1,4 +0,4 @@ | ||
const React = require('react'); | ||
const ReactTestUtils = require('react-addons-test-utils'); | ||
const FormatNumberInput = require('../src/number_format'); | ||
import React from 'react'; | ||
import ReactTestUtils from 'react-addons-test-utils'; | ||
import FormatNumberInput from '../src/number_format'; | ||
@@ -28,2 +28,3 @@ /*** format_number input as input ****/ | ||
it('should listen change event and formmat currency properly', () => { | ||
@@ -42,2 +43,29 @@ const component = ReactTestUtils.renderIntoDocument(<FormatNumberInput thousandSeparator={true} prefix={'$'} />); | ||
it('should maintain decimal points', () => { | ||
const component = ReactTestUtils.renderIntoDocument(<FormatNumberInput thousandSeparator={true} prefix={'$'} />); | ||
const input = ReactTestUtils.findRenderedDOMComponentWithTag( | ||
component, 'input' | ||
); | ||
input.value = "2456981.89"; | ||
ReactTestUtils.Simulate.input(input); | ||
expect(input.value).toEqual("$2,456,981.89"); | ||
}); | ||
it('should support custom thousand seperator', () => { | ||
const component = ReactTestUtils.renderIntoDocument(<FormatNumberInput thousandSeparator={'.'} decimalSeperator={','} prefix={'$'} />); | ||
const input = ReactTestUtils.findRenderedDOMComponentWithTag( | ||
component, 'input' | ||
); | ||
input.value = "2456981,89"; | ||
ReactTestUtils.Simulate.input(input); | ||
expect(input.value).toEqual("$2.456.981,89"); | ||
}); | ||
it('should have proper intermediate formatting', () => { | ||
@@ -44,0 +72,0 @@ const component = ReactTestUtils.renderIntoDocument(<FormatNumberInput format="#### #### #### ####" />); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
73758
1424
2
101