34 |
49 |
50 | Raw: {this.state.raw}
51 | Display: {this.state.display}
52 |
53 | )
54 | }
55 | }
56 |
57 | ReactDOM.render(, document.getElementById('app'))
58 |
--------------------------------------------------------------------------------
/example/src/example.less:
--------------------------------------------------------------------------------
1 | /*
2 | // Examples Stylesheet
3 | // -------------------
4 | */
5 |
6 | body {
7 | font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
8 | font-size: 14px;
9 | color: #333;
10 | margin: 0;
11 | padding: 0;
12 | }
13 |
14 | a {
15 | color: #08c;
16 | text-decoration: none;
17 | }
18 |
19 | a:hover {
20 | text-decoration: underline;
21 | }
22 |
23 | .container {
24 | margin-left: auto;
25 | margin-right: auto;
26 | max-width: 720px;
27 | padding: 1em;
28 | }
29 |
30 | .footer {
31 | margin-top: 50px;
32 | border-top: 1px solid #eee;
33 | padding: 20px 0;
34 | font-size: 12px;
35 | color: #999;
36 | }
37 |
38 | h1, h2, h3, h4, h5, h6 {
39 | color: #222;
40 | font-weight: 100;
41 | margin: 0.5em 0;
42 | }
43 |
44 | label {
45 | color: #999;
46 | display: inline-block;
47 | font-size: 0.85em;
48 | font-weight: bold;
49 | margin: 1em 0;
50 | text-transform: uppercase;
51 | }
52 |
53 | .hint {
54 | margin: 15px 0;
55 | font-style: italic;
56 | color: #999;
57 | }
58 |
59 | .my-input-class {
60 | background-color: #afafaf;
61 | }
62 |
--------------------------------------------------------------------------------
/example/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | SimpleCurrencyInput
4 |
5 |
6 |
7 |
8 |
Simple Currency Input
9 |
10 |
11 |
12 |
13 |
14 |
15 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp')
2 | var initGulpTasks = require('react-component-gulp-tasks')
3 |
4 | /**
5 | * Tasks are added by the react-component-gulp-tasks package
6 | *
7 | * See https://github.com/JedWatson/react-component-gulp-tasks
8 | * for documentation.
9 | *
10 | * You can also add your own additional gulp tasks if you like.
11 | */
12 |
13 | var taskConfig = {
14 |
15 | component: {
16 | name: 'SimpleCurrencyInput',
17 | dependencies: [
18 | 'classnames',
19 | 'react',
20 | 'prop-types',
21 | 'react-dom'
22 | ],
23 | lib: 'lib'
24 | },
25 |
26 | example: {
27 | src: 'example/src',
28 | dist: 'example/dist',
29 | files: [
30 | 'index.html',
31 | '.gitignore'
32 | ],
33 | scripts: [
34 | 'example.js'
35 | ],
36 | less: [
37 | 'example.less'
38 | ]
39 | }
40 |
41 | }
42 |
43 | initGulpTasks(gulp, taskConfig)
44 |
--------------------------------------------------------------------------------
/lib/SimpleCurrencyInput.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, '__esModule', {
4 | value: true
5 | });
6 |
7 | 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; }; })();
8 |
9 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
10 |
11 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
12 |
13 | 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; }
14 |
15 | var React = require('react');
16 | var PropTypes = require('prop-types');
17 |
18 | var SimpleCurrencyInput = (function (_React$Component) {
19 | _inherits(SimpleCurrencyInput, _React$Component);
20 |
21 | function SimpleCurrencyInput(props) {
22 | _classCallCheck(this, SimpleCurrencyInput);
23 |
24 | _get(Object.getPrototypeOf(SimpleCurrencyInput.prototype), 'constructor', this).call(this, props);
25 |
26 | this.onInputType = this.onInputType.bind(this);
27 | this.formattedRawValue = this.formattedRawValue.bind(this);
28 | this.getRawValue = this.getRawValue.bind(this);
29 |
30 | this.state = {
31 | rawValue: this.props.value,
32 | tabIndex: this.props.tabIndex,
33 | readOnly: this.props.readOnly
34 | };
35 | }
36 |
37 | _createClass(SimpleCurrencyInput, [{
38 | key: 'componentWillMount',
39 | value: function componentWillMount() {
40 | this.notifyParentWithRawValue(this.state.rawValue);
41 | }
42 | }, {
43 | key: 'componentWillReceiveProps',
44 | value: function componentWillReceiveProps(nextProps) {
45 | if (nextProps.value || nextProps.value === 0) {
46 | this.setState({
47 | rawValue: nextProps.value
48 | });
49 | }
50 | }
51 | }, {
52 | key: 'onInputType',
53 | value: function onInputType(event) {
54 | var input = event.target.value;
55 | var rawValue = this.getRawValue(input);
56 | if (!rawValue) {
57 | rawValue = 0;
58 | }
59 |
60 | this.notifyParentWithRawValue(rawValue);
61 |
62 | this.setState({
63 | rawValue: rawValue
64 | });
65 | }
66 | }, {
67 | key: 'notifyParentWithRawValue',
68 | value: function notifyParentWithRawValue(rawValue) {
69 | var display = this.formattedRawValue(rawValue);
70 | this.props.onInputChange(rawValue, display);
71 | }
72 | }, {
73 | key: 'getRawValue',
74 | value: function getRawValue(displayedValue) {
75 | var result = displayedValue;
76 |
77 | result = removeOccurrences(result, this.props.delimiter);
78 | result = removeOccurrences(result, this.props.separator);
79 | result = removeOccurrences(result, this.props.unit);
80 |
81 | var intValue = parseInt(result);
82 |
83 | return intValue;
84 | }
85 | }, {
86 | key: 'formattedRawValue',
87 | value: function formattedRawValue(rawValue) {
88 | var minChars = '0'.length + this.props.precision;
89 |
90 | var result = '';
91 | result = '' + rawValue;
92 |
93 | if (result.length < minChars) {
94 | var leftZeroesToAdd = minChars - result.length;
95 | result = '' + repeatZeroes(leftZeroesToAdd) + result;
96 | }
97 |
98 | var beforeSeparator = result.slice(0, result.length - this.props.precision);
99 | var afterSeparator = result.slice(result.length - this.props.precision);
100 |
101 | if (beforeSeparator.length > 3) {
102 | var chars = beforeSeparator.split('').reverse();
103 | var withDots = '';
104 | for (var i = chars.length - 1; i >= 0; i--) {
105 | var char = chars[i];
106 | var dot = i % 3 === 0 ? this.props.delimiter : '';
107 | withDots = '' + withDots + char + dot;
108 | }
109 | withDots = withDots.substring(0, withDots.length - 1);
110 | beforeSeparator = withDots;
111 | }
112 | result = beforeSeparator + this.props.separator + afterSeparator;
113 |
114 | if (this.props.unit) {
115 | result = this.props.unit + ' ' + result;
116 | }
117 |
118 | return result;
119 | }
120 | }, {
121 | key: 'render',
122 | value: function render() {
123 | return React.createElement('input', {
124 | id: this.props.id,
125 | className: this.props.className,
126 | onBlur: this.props.onInputBlur,
127 | onFocus: this.props.onInputFocus,
128 | onChange: this.onInputType,
129 | value: this.formattedRawValue(this.state.rawValue),
130 | disabled: this.props.disabled,
131 | autoFocus: this.props.autoFocus,
132 | tabIndex: this.state.tabIndex,
133 | readOnly: this.state.readOnly,
134 | autoComplete: this.props.autoComplete,
135 | autoCorrect: this.props.autoCorrect,
136 | name: this.props.name,
137 | placeholder: this.props.placeholder
138 | });
139 | }
140 | }]);
141 |
142 | return SimpleCurrencyInput;
143 | })(React.Component);
144 |
145 | var repeatZeroes = function repeatZeroes(times) {
146 | var result = '';
147 | var i = 0;
148 | for (i = 0; i < times; i++) {
149 | result += '0';
150 | }
151 |
152 | return result;
153 | };
154 |
155 | var removeOccurrences = function removeOccurrences(from, toRemove) {
156 | toRemove = toRemove.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
157 | var re = new RegExp(toRemove, 'g');
158 | return from.replace(re, '');
159 | };
160 |
161 | SimpleCurrencyInput.propTypes = {
162 | id: PropTypes.string,
163 | autoFocus: PropTypes.bool,
164 | delimiter: PropTypes.string,
165 | disabled: PropTypes.bool,
166 | onInputChange: PropTypes.func,
167 | onInputBlur: PropTypes.func,
168 | onInputFocus: PropTypes.func,
169 | precision: PropTypes.number,
170 | readOnly: PropTypes.bool,
171 | separator: PropTypes.string,
172 | tabIndex: PropTypes.number,
173 | unit: PropTypes.string,
174 | value: PropTypes.number.isRequired
175 | };
176 |
177 | SimpleCurrencyInput.defaultProps = {
178 | value: 0,
179 | precision: 2,
180 | separator: '.',
181 | delimiter: ',',
182 | unit: '',
183 | disabled: false,
184 | autoFocus: false,
185 | onInputChange: function onInputChange() {},
186 | onInputBlur: function onInputBlur() {},
187 | onInputFocus: function onInputFocus() {}
188 | };
189 |
190 | exports['default'] = SimpleCurrencyInput;
191 | module.exports = exports['default'];
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-simple-currency",
3 | "version": "1.0.16",
4 | "description": "A react input wrapper to mask and handle currency values",
5 | "main": "lib/SimpleCurrencyInput.js",
6 | "author": "Leonardo Wistuba de França",
7 | "homepage": "https://github.com/leonardowf/react-simple-currency",
8 | "repository": {
9 | "type": "git",
10 | "url": "https://github.com/leonardowf/react-simple-currency.git"
11 | },
12 | "bugs": {
13 | "url": "https://github.com/leonardowf/react-simple-currency/issues"
14 | },
15 | "dependencies": {
16 | "classnames": "^2.1.2",
17 | "prop-types": "^15.6.0"
18 | },
19 | "devDependencies": {
20 | "babel-eslint": "^4.1.3",
21 | "eslint": "^1.6.0",
22 | "eslint-plugin-react": "^3.5.1",
23 | "gulp": "^3.9.0",
24 | "react": "^0.14.0",
25 | "react-component-gulp-tasks": "^0.7.6",
26 | "react-dom": "^0.14.0"
27 | },
28 | "peerDependencies": {
29 | "react": "^0.14.0"
30 | },
31 | "browserify-shim": {
32 | "react": "global:React"
33 | },
34 | "scripts": {
35 | "build": "gulp clean && NODE_ENV=production gulp build",
36 | "examples": "gulp dev:server",
37 | "lint": "eslint ./; true",
38 | "publish:site": "NODE_ENV=production gulp publish:examples",
39 | "release": "NODE_ENV=production gulp release",
40 | "start": "gulp dev",
41 | "test": "echo \"no tests yet\" && exit 0",
42 | "watch": "gulp watch:lib"
43 | },
44 | "keywords": [
45 | "react",
46 | "react-component",
47 | "currency",
48 | "money",
49 | "mask",
50 | "masker",
51 | "input",
52 | "value"
53 | ]
54 | }
55 |
--------------------------------------------------------------------------------
/src/SimpleCurrencyInput.js:
--------------------------------------------------------------------------------
1 | var React = require('react')
2 | var PropTypes = require('prop-types')
3 |
4 | class SimpleCurrencyInput extends React.Component {
5 | constructor(props) {
6 | super(props)
7 |
8 | this.onInputType = this.onInputType.bind(this)
9 | this.formattedRawValue = this.formattedRawValue.bind(this)
10 | this.getRawValue = this.getRawValue.bind(this)
11 |
12 | this.state = {
13 | rawValue: this.props.value,
14 | tabIndex: this.props.tabIndex,
15 | readOnly: this.props.readOnly
16 | }
17 | }
18 |
19 | componentWillMount() {
20 | this.notifyParentWithRawValue(this.state.rawValue)
21 | }
22 |
23 | componentWillReceiveProps (nextProps) {
24 | if (nextProps.value || nextProps.value === 0) {
25 | this.setState({
26 | rawValue: nextProps.value
27 | })
28 | }
29 | }
30 |
31 | onInputType (event) {
32 | const input = event.target.value
33 | let rawValue = this.getRawValue(input)
34 | if (!rawValue) {
35 | rawValue = 0
36 | }
37 |
38 | this.notifyParentWithRawValue(rawValue)
39 |
40 | this.setState({
41 | rawValue
42 | })
43 | }
44 |
45 | notifyParentWithRawValue (rawValue) {
46 | let display = this.formattedRawValue(rawValue)
47 | this.props.onInputChange(rawValue, display)
48 | }
49 |
50 | getRawValue (displayedValue) {
51 | let result = displayedValue
52 |
53 | result = removeOccurrences(result, this.props.delimiter)
54 | result = removeOccurrences(result, this.props.separator)
55 | result = removeOccurrences(result, this.props.unit)
56 |
57 | let intValue = parseInt(result)
58 |
59 | return intValue
60 | }
61 |
62 | formattedRawValue (rawValue) {
63 | const minChars = '0'.length + this.props.precision
64 |
65 | let result = ''
66 | result = `${rawValue}`
67 |
68 | if (result.length < minChars) {
69 | const leftZeroesToAdd = minChars - result.length
70 | result = `${repeatZeroes(leftZeroesToAdd)}${result}`
71 | }
72 |
73 | let beforeSeparator = result.slice(0, result.length - this.props.precision)
74 | let afterSeparator = result.slice(result.length - this.props.precision)
75 |
76 | if (beforeSeparator.length > 3) {
77 | var chars = beforeSeparator.split('').reverse()
78 | let withDots = ''
79 | for (var i = chars.length -1; i >= 0; i--) {
80 | let char = chars[i]
81 | let dot = i % 3 === 0 ? this.props.delimiter : ''
82 | withDots = `${withDots}${char}${dot}`
83 | }
84 | withDots = withDots.substring(0, withDots.length - 1)
85 | beforeSeparator = withDots
86 | }
87 | result = beforeSeparator + this.props.separator + afterSeparator
88 |
89 | if (this.props.unit) {
90 | result = `${this.props.unit} ${result}`
91 | }
92 |
93 | return result
94 | }
95 |
96 | render() {
97 | return (
98 |
114 | )
115 | }
116 | }
117 |
118 | const repeatZeroes = (times) => {
119 | let result = ''
120 | let i = 0
121 | for (i = 0; i < times; i++) {
122 | result += '0'
123 | }
124 |
125 | return result
126 | }
127 |
128 | const removeOccurrences = (from, toRemove) => {
129 | toRemove = toRemove.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&')
130 | var re = new RegExp(toRemove, 'g')
131 | return from.replace(re, '')
132 | }
133 |
134 | SimpleCurrencyInput.propTypes = {
135 | id: PropTypes.string,
136 | autoFocus: PropTypes.bool,
137 | delimiter: PropTypes.string,
138 | disabled: PropTypes.bool,
139 | onInputChange: PropTypes.func,
140 | onInputBlur: PropTypes.func,
141 | onInputFocus: PropTypes.func,
142 | precision: PropTypes.number,
143 | readOnly: PropTypes.bool,
144 | separator: PropTypes.string,
145 | tabIndex: PropTypes.number,
146 | unit: PropTypes.string,
147 | value: PropTypes.number.isRequired
148 | }
149 |
150 | SimpleCurrencyInput.defaultProps = {
151 | value: 0,
152 | precision: 2,
153 | separator: '.',
154 | delimiter: ',',
155 | unit: '',
156 | disabled: false,
157 | autoFocus: false,
158 | onInputChange: () => {},
159 | onInputBlur: () => {},
160 | onInputFocus: () => {}
161 | }
162 |
163 | export default SimpleCurrencyInput
164 |
--------------------------------------------------------------------------------