├── .gitignore ├── .npmignore ├── example ├── components │ ├── Snippet │ │ ├── snippet.css │ │ └── index.js │ ├── Layout │ │ ├── index.js │ │ ├── layout.css │ │ └── fonts.css │ └── ComponentSnippet │ │ ├── componentSnippet.css │ │ └── index.js └── index.js ├── .babelrc ├── prettier.config.js ├── docs └── index.html ├── .eslintrc.js ├── CHANGELOG.md ├── webpack.config.js ├── README.md ├── package.json └── src └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | logs 2 | *.log 3 | npm-debug.log.* 4 | node_modules 5 | dist 6 | !docs/dist -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | docs 2 | node_modules 3 | .eslintrc.js 4 | .gitignore 5 | yarn.lock 6 | webpack.config.js 7 | -------------------------------------------------------------------------------- /example/components/Snippet/snippet.css: -------------------------------------------------------------------------------- 1 | .wrapper{ 2 | background: #f8f9f9!important; 3 | font-size: 0.9em; 4 | } -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "env", 4 | "react" 5 | ], 6 | "plugins": [ 7 | ["transform-object-rest-spread"] 8 | ] 9 | } -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "singleQuote": false, 3 | "trailingComma": "es5", 4 | "bracketSpacing": true, 5 | "jsxBracketSameLine": true, 6 | "printWidth": 100, 7 | "parser": "babylon", 8 | } -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | react-numeric 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/components/Layout/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styles from "./layout.css"; 3 | import "./fonts.css"; 4 | 5 | const Layout = props => { 6 | return
{props.children}
; 7 | }; 8 | 9 | export default Layout; 10 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | "eslint:recommended", 4 | "plugin:react/recommended", 5 | "prettier", 6 | ], 7 | plugins: [ 8 | "react", 9 | "prettier", 10 | ], 11 | rules: { 12 | }, 13 | parser: "babel-eslint", 14 | env: { 15 | "es6": true, 16 | "node": true, 17 | "browser": true, 18 | "jest": true, 19 | }, 20 | }; -------------------------------------------------------------------------------- /example/components/Snippet/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styles from "./snippet.css"; 3 | import SyntaxHighlighter from "react-syntax-highlighter/prism"; 4 | import dark from "react-syntax-highlighter/styles/prism/coy.js"; 5 | 6 | const ComponentSnippet = props => { 7 | return ( 8 | 9 | {props.children} 10 | 11 | ); 12 | }; 13 | 14 | export default ComponentSnippet; 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | 8 | ## [1.0.0] - 2019-07-02 9 | ### Added 10 | `autoFocus`, `placeholder` `unselectable`, `size` and `id` props for input added by [@sbusch](https://github.com/sbusch) 11 | Added changelog 12 | 13 | ### Changed 14 | - `prop-types` moved to peer dependencies from dependencies. 15 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin') 3 | 4 | module.exports = { 5 | entry: path.resolve("./example/index.js"), 6 | output: { 7 | path: path.resolve("./docs"), 8 | filename: "[name].js" 9 | }, 10 | module: { 11 | rules: [ 12 | { 13 | test: /\.js$/, 14 | loader: "babel-loader", 15 | exclude: /node_modules/ 16 | }, 17 | { 18 | test: /\.css$/, 19 | use: ["style-loader", "css-loader?modules"], 20 | include: path.resolve("./example") 21 | }, 22 | { 23 | test: /\.css$/, 24 | use: ["style-loader", "css-loader"], 25 | include: /node_modules/ 26 | }, 27 | { 28 | test: /\.(jpg|png)$/, 29 | use: ["file-loader"] 30 | } 31 | ] 32 | }, 33 | devServer: { 34 | publicPath: "/", 35 | contentBase: path.join(__dirname, "example"), 36 | hot: true 37 | }, 38 | plugins: [new HtmlWebpackPlugin({ 39 | title: 'react-numeric', 40 | })], 41 | }; 42 | -------------------------------------------------------------------------------- /example/components/ComponentSnippet/componentSnippet.css: -------------------------------------------------------------------------------- 1 | .wrapper{ 2 | background: #f8f9f9; 3 | font-size: 0.9em; 4 | margin-top: 2em; 5 | margin-bottom: 6em; 6 | position: relative; 7 | } 8 | 9 | .content{ 10 | position: relative; 11 | z-index: 1; 12 | background: #f8f9f9!important; 13 | } 14 | 15 | .preview{ 16 | display: flex; 17 | justify-content: center; 18 | align-items: center; 19 | min-height: 12em; 20 | } 21 | 22 | .code{ 23 | background: #f8f9f9!important; 24 | } 25 | 26 | .buttons{ 27 | position: absolute; 28 | top: 100%; 29 | right: 0em; 30 | } 31 | 32 | .button{ 33 | background-color: rgb(248, 249, 249); 34 | padding: 1em; 35 | border: 1px solid transparent; 36 | font-size: 0.8em; 37 | cursor: pointer; 38 | outline: 0; 39 | color: #3d91ff; 40 | } 41 | 42 | .button:hover{ 43 | border-color: #3d91ff; 44 | } 45 | 46 | .button:first-child{ 47 | border-bottom-left-radius: 4px; 48 | } 49 | 50 | .button:last-child{ 51 | border-bottom-right-radius: 4px; 52 | } 53 | 54 | .passiveButton{ 55 | background: #f1f2f2; 56 | color: #666666; 57 | } 58 | 59 | input{ 60 | font-size: 1.6em; 61 | padding: 0.5em; 62 | } 63 | 64 | input:focus{ 65 | outline:2px solid #3d91ff; 66 | } -------------------------------------------------------------------------------- /example/components/Layout/layout.css: -------------------------------------------------------------------------------- 1 | html{ 2 | height: 100%; 3 | background-color: #e7eff2; 4 | color: #637381; 5 | overflow-y: scroll; 6 | font-family: 'Open Sans', sans-serif; 7 | font-size: 16px; 8 | } 9 | 10 | body{ 11 | min-height: 100vh; 12 | margin: 0; 13 | padding: 2em; 14 | text-align: center; 15 | 16 | } 17 | 18 | .wrapper{ 19 | padding: 40px 40px 40px 48px; 20 | /* box-shadow: 0 12px 36px rgba(0,0,0,.2); */ 21 | background-color: #fff; 22 | max-width: 970px; 23 | margin: 6em auto 0 auto; 24 | text-align: left; 25 | } 26 | 27 | h1{ 28 | font-size: 2.5em; 29 | font-weight: 600; 30 | color: #161d25; 31 | font-family: 'PT Sans', sans-serif; 32 | max-width: 600px; 33 | } 34 | 35 | h2{ 36 | color: #161d25; 37 | font-size: 1.6em; 38 | font-weight: 400; 39 | font-family: 'PT Sans', sans-serif; 40 | max-width: 600px; 41 | } 42 | 43 | blockquote{ 44 | font-size: 1.6em; 45 | font-weight: 400; 46 | font-family: 'PT Sans', sans-serif; 47 | box-shadow: -7px 0px #3ecf8e; 48 | margin: 1em 0.3em; 49 | padding-left: 1em; 50 | max-width: 600px; 51 | } 52 | 53 | .blockquote{ 54 | font-size: 1.6em; 55 | font-weight: 400; 56 | font-family: 'PT Sans', sans-serif; 57 | margin: 0.3em; 58 | max-width: 600px; 59 | } 60 | 61 | p{ 62 | font-weight: 500; 63 | max-width: 600px; 64 | } 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-numeric 2 | 3 | [![npm](https://img.shields.io/npm/l/react-numeric.svg?style=flat-square)]() 4 | [![npm](https://img.shields.io/npm/v/react-numeric.svg?style=flat-square)](https://www.npmjs.com/package/react-numeric) 5 | 6 | 7 | A react component for formatted number form fields 8 | > react-numeric is a wrapper component for [autonumeric](https://github.com/autoNumeric/autoNumeric). 9 | 10 | ## Installition 11 | 12 | ```sh 13 | yarn add react-numeric 14 | # or 15 | npm install react-numeric --save 16 | ``` 17 | 18 | ## Usage 19 | 20 | ```jsx 21 | import ReactNumeric from 'react-numeric'; 22 | 23 | export function USDMoneyInput(props){ 24 | const { value } = props; // number typed 25 | return ( 26 | { 33 | console.log(event.target.value); // '1,234.5 $' 34 | console.log(value); // 1234.5 35 | }} 36 | /> 37 | ); 38 | } 39 | 40 | // You can use predefinedOptions 41 | import { predefinedOptions } from 'react-numeric'; 42 | 43 | export function PossitiveUSDMoneyInput(props){ 44 | const { value } = props; // number typed 45 | return ( 46 | this.setState({ value })} 50 | /> 51 | ); 52 | } 53 | 54 | // if you want to store value as string typed 55 | export function NumberInput(props){ 56 | const { value } = props; // string typed 57 | return ( 58 | this.setState({ value })} 62 | /> 63 | ); 64 | } 65 | ``` 66 | -------------------------------------------------------------------------------- /example/components/ComponentSnippet/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styles from "./componentSnippet.css"; 3 | import SyntaxHighlighter from "react-syntax-highlighter/prism"; 4 | import dark from "react-syntax-highlighter/styles/prism/coy.js"; 5 | import cx from "classnames"; 6 | import PropTypes from "prop-types"; 7 | 8 | class ComponentSnippet extends React.Component { 9 | constructor(props) { 10 | super(props); 11 | this.state = { 12 | mode: props.initialMode, 13 | }; 14 | } 15 | 16 | render() { 17 | const { mode } = this.state; 18 | const { preview, code } = this.props; 19 | return ( 20 |
21 |
22 | {mode === "code" ? ( 23 | 24 | {code} 25 | 26 | ) : ( 27 |
{preview}
28 | )} 29 |
30 |
31 | 38 | 45 |
46 |
47 | ); 48 | } 49 | } 50 | 51 | ComponentSnippet.propTypes = { 52 | initialMode: PropTypes.oneOf(["preview", "code"]), 53 | }; 54 | 55 | ComponentSnippet.defaultProps = { 56 | initialMode: "preview", 57 | }; 58 | 59 | export default ComponentSnippet; 60 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-numeric", 3 | "description": "A react component for formatted number form fields", 4 | "version": "1.0.0", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/mkg0/react-numeric" 8 | }, 9 | "main": "dist/index.js", 10 | "keywords": [ 11 | "autonumeric", 12 | "currency", 13 | "money", 14 | "monetary", 15 | "Euro", 16 | "Dollar", 17 | "Pound", 18 | "number", 19 | "numeric", 20 | "format", 21 | "react", 22 | "numeric" 23 | ], 24 | "author": "Mehmet Kamil Morcay (https://github.com/mkg0)", 25 | "license": "MIT", 26 | "dependencies": { 27 | "autonumeric": "^4.4.0" 28 | }, 29 | "devDependencies": { 30 | "babel-cli": "^6.26.0", 31 | "babel-eslint": "^8.2.2", 32 | "babel-loader": "^7.1.4", 33 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 34 | "babel-preset-env": "^1.6.1", 35 | "babel-preset-react": "^6.24.1", 36 | "classnames": "^2.2.5", 37 | "css-loader": "^0.28.11", 38 | "eslint": "^4.19.1", 39 | "eslint-config-prettier": "^2.9.0", 40 | "eslint-plugin-prettier": "^2.6.0", 41 | "eslint-plugin-react": "^7.7.0", 42 | "html-webpack-plugin": "^3.2.0", 43 | "prettier": "^1.11.1", 44 | "react": "^16.2.0", 45 | "react-dom": "^16.2.0", 46 | "react-syntax-highlighter": "^7.0.1", 47 | "style-loader": "^0.20.3", 48 | "webpack": "^4.5.0", 49 | "webpack-cli": "^2.0.14", 50 | "webpack-dev-server": "^3.1.3" 51 | }, 52 | "peerDependencies": { 53 | "react": ">=15.0.0", 54 | "prop-types": "^15.6.1" 55 | }, 56 | "scripts": { 57 | "build": "yarn build-library && yarn build-demo", 58 | "build-library": "NODE_ENV=production babel ./src --out-dir ./dist", 59 | "build-demo": "webpack -p", 60 | "clear": "rm -rf dist docs", 61 | "prebuild": "yarn clear && yarn lint", 62 | "dev": "webpack-dev-server --hot --mode 'development'", 63 | "lint": "eslint 'src/**/*.js'", 64 | "prettier": "prettier src/**/*.js example/**/*.js --write" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import ReactDOM from "react-dom"; 3 | import ReactNumeric, { predefinedOptions } from "../src"; 4 | import Snippet from "./components/Snippet"; 5 | import ComponentSnippet from "./components/ComponentSnippet"; 6 | 7 | import Layout from "./components/Layout"; 8 | 9 | class DemoPage extends Component { 10 | constructor(props) { 11 | super(props); 12 | this.state = { 13 | intro: 12345, 14 | example1: 12345, 15 | example2: "12345", 16 | example3: 12345, 17 | }; 18 | } 19 | render() { 20 | return ( 21 | 22 |

react-numeric

23 |
A react component for formatted numeric values.
24 |

25 | react-numeric is a wrapper component of{" "} 26 | 27 | autonumeric 28 | . 29 |

30 | 31 | { 39 | this.setState({ value }); 40 | }} /> 41 | `} 42 | preview={ 43 | { 46 | console.info("onChange", params); 47 | this.setState({ intro: params[1] }); 48 | }} 49 | /> 50 | } 51 | /> 52 |

Installition

53 | 54 | {` 55 | yarn add react-numeric 56 | `} 57 | 58 |

If you don't use yarn

59 | 60 | {` 61 | npm install react-numeric --save 62 | `} 63 | 64 | 65 |

Usage & Demos

66 | 67 | this.setState({example1: value}) }} /> 77 | `} 78 | preview={ 79 |
80 | { 87 | console.info("onChange", params); 88 | this.setState({ example1: params[1] }); 89 | }} 90 | /> 91 |
92 | } 93 | /> 94 |

if you want to store value as string typed

95 | this.setState({example2: value}) }} /> 102 | `} 103 | preview={ 104 | { 108 | console.info("onChange", params); 109 | this.setState({ example2: params[1] }); 110 | }} 111 | /> 112 | } 113 | /> 114 | 115 |

You can use predefinedOptions

116 | this.setState({example3: value}) }} /> 123 | `} 124 | preview={ 125 | { 129 | console.info("onChange", params); 130 | this.setState({ example3: params[1] }); 131 | }} 132 | /> 133 | } 134 | /> 135 |
136 | ); 137 | } 138 | } 139 | 140 | const root = document.createElement("div"); 141 | document.body.appendChild(root); 142 | ReactDOM.render(, root); 143 | -------------------------------------------------------------------------------- /example/components/Layout/fonts.css: -------------------------------------------------------------------------------- 1 | /* cyrillic-ext */ 2 | @font-face { 3 | font-family: 'Open Sans'; 4 | font-style: normal; 5 | font-weight: 400; 6 | src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/mem8YaGs126MiZpBA-UFWJ0bf8pkAp6a.woff2) format('woff2'); 7 | unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; 8 | } 9 | /* cyrillic */ 10 | @font-face { 11 | font-family: 'Open Sans'; 12 | font-style: normal; 13 | font-weight: 400; 14 | src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/mem8YaGs126MiZpBA-UFUZ0bf8pkAp6a.woff2) format('woff2'); 15 | unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; 16 | } 17 | /* greek-ext */ 18 | @font-face { 19 | font-family: 'Open Sans'; 20 | font-style: normal; 21 | font-weight: 400; 22 | src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/mem8YaGs126MiZpBA-UFWZ0bf8pkAp6a.woff2) format('woff2'); 23 | unicode-range: U+1F00-1FFF; 24 | } 25 | /* greek */ 26 | @font-face { 27 | font-family: 'Open Sans'; 28 | font-style: normal; 29 | font-weight: 400; 30 | src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/mem8YaGs126MiZpBA-UFVp0bf8pkAp6a.woff2) format('woff2'); 31 | unicode-range: U+0370-03FF; 32 | } 33 | /* vietnamese */ 34 | @font-face { 35 | font-family: 'Open Sans'; 36 | font-style: normal; 37 | font-weight: 400; 38 | src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/mem8YaGs126MiZpBA-UFWp0bf8pkAp6a.woff2) format('woff2'); 39 | unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; 40 | } 41 | /* latin-ext */ 42 | @font-face { 43 | font-family: 'Open Sans'; 44 | font-style: normal; 45 | font-weight: 400; 46 | src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/mem8YaGs126MiZpBA-UFW50bf8pkAp6a.woff2) format('woff2'); 47 | unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; 48 | } 49 | /* latin */ 50 | @font-face { 51 | font-family: 'Open Sans'; 52 | font-style: normal; 53 | font-weight: 400; 54 | src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/mem8YaGs126MiZpBA-UFVZ0bf8pkAg.woff2) format('woff2'); 55 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 56 | } 57 | /* cyrillic-ext */ 58 | @font-face { 59 | font-family: 'PT Sans'; 60 | font-style: normal; 61 | font-weight: 400; 62 | src: local('PT Sans'), local('PTSans-Regular'), url(https://fonts.gstatic.com/s/ptsans/v9/jizaRExUiTo99u79D0-ExcOPIDUg-g.woff2) format('woff2'); 63 | unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; 64 | } 65 | /* cyrillic */ 66 | @font-face { 67 | font-family: 'PT Sans'; 68 | font-style: normal; 69 | font-weight: 400; 70 | src: local('PT Sans'), local('PTSans-Regular'), url(https://fonts.gstatic.com/s/ptsans/v9/jizaRExUiTo99u79D0aExcOPIDUg-g.woff2) format('woff2'); 71 | unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; 72 | } 73 | /* latin-ext */ 74 | @font-face { 75 | font-family: 'PT Sans'; 76 | font-style: normal; 77 | font-weight: 400; 78 | src: local('PT Sans'), local('PTSans-Regular'), url(https://fonts.gstatic.com/s/ptsans/v9/jizaRExUiTo99u79D0yExcOPIDUg-g.woff2) format('woff2'); 79 | unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; 80 | } 81 | /* latin */ 82 | @font-face { 83 | font-family: 'PT Sans'; 84 | font-style: normal; 85 | font-weight: 400; 86 | src: local('PT Sans'), local('PTSans-Regular'), url(https://fonts.gstatic.com/s/ptsans/v9/jizaRExUiTo99u79D0KExcOPIDU.woff2) format('woff2'); 87 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 88 | } 89 | /* cyrillic-ext */ 90 | @font-face { 91 | font-family: 'PT Sans'; 92 | font-style: normal; 93 | font-weight: 700; 94 | src: local('PT Sans Bold'), local('PTSans-Bold'), url(https://fonts.gstatic.com/s/ptsans/v9/jizfRExUiTo99u79B_mh0OOtLR8a8zILig.woff2) format('woff2'); 95 | unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; 96 | } 97 | /* cyrillic */ 98 | @font-face { 99 | font-family: 'PT Sans'; 100 | font-style: normal; 101 | font-weight: 700; 102 | src: local('PT Sans Bold'), local('PTSans-Bold'), url(https://fonts.gstatic.com/s/ptsans/v9/jizfRExUiTo99u79B_mh0OqtLR8a8zILig.woff2) format('woff2'); 103 | unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; 104 | } 105 | /* latin-ext */ 106 | @font-face { 107 | font-family: 'PT Sans'; 108 | font-style: normal; 109 | font-weight: 700; 110 | src: local('PT Sans Bold'), local('PTSans-Bold'), url(https://fonts.gstatic.com/s/ptsans/v9/jizfRExUiTo99u79B_mh0OCtLR8a8zILig.woff2) format('woff2'); 111 | unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; 112 | } 113 | /* latin */ 114 | @font-face { 115 | font-family: 'PT Sans'; 116 | font-style: normal; 117 | font-weight: 700; 118 | src: local('PT Sans Bold'), local('PTSans-Bold'), url(https://fonts.gstatic.com/s/ptsans/v9/jizfRExUiTo99u79B_mh0O6tLR8a8zI.woff2) format('woff2'); 119 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 120 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import PropTypes from "prop-types"; 3 | import AutoNumeric from "autonumeric"; 4 | 5 | export default class ReactNumeric extends React.Component { 6 | constructor(props) { 7 | super(props); 8 | this.getValue = this.getValue.bind(this); 9 | this.callEventHandler = this.callEventHandler.bind(this); 10 | } 11 | componentDidMount() { 12 | this.autonumeric = new AutoNumeric(this.input, this.props.value, { 13 | ...this.props.preDefined, 14 | ...this.props, 15 | onChange: undefined, 16 | onFocus: undefined, 17 | onBlur: undefined, 18 | onKeyPress: undefined, 19 | onKeyUp: undefined, 20 | onKeyDown: undefined, 21 | watchExternalChanges: false, 22 | }); 23 | } 24 | componentWillUnmount() { 25 | if (this.autonumeric) this.autonumeric.remove(); 26 | } 27 | 28 | componentWillReceiveProps(newProps) { 29 | const isOptionsChanged = 30 | JSON.stringify({ ...this.props, value: undefined }) !== 31 | JSON.stringify({ ...newProps, value: undefined }); 32 | const isValueChanged = 33 | this.props.value !== newProps.value && this.getValue() !== newProps.value; 34 | if (isValueChanged) { 35 | this.autonumeric.set(newProps.value); 36 | } 37 | if (isOptionsChanged) { 38 | this.autonumeric.update({ 39 | ...newProps.preDefined, 40 | ...newProps, 41 | onChange: undefined, 42 | onFocus: undefined, 43 | onBlur: undefined, 44 | onKeyPress: undefined, 45 | onKeyUp: undefined, 46 | onKeyDown: undefined, 47 | watchExternalChanges: false, 48 | }); 49 | } 50 | } 51 | getValue() { 52 | if (!this.autonumeric) return; 53 | const valueMapper = { 54 | string: numeric => numeric.getNumericString(), 55 | number: numeric => numeric.getNumber(), 56 | }; 57 | return valueMapper[this.props.outputFormat](this.autonumeric); 58 | } 59 | callEventHandler(event, eventName) { 60 | if (!this.props[eventName]) return; 61 | this.props[eventName](event, this.getValue()); 62 | } 63 | render() { 64 | const inputProps = {}; 65 | [ 66 | "id", 67 | "className", 68 | "style", 69 | "disabled", 70 | "type", 71 | "name", 72 | "tabIndex", 73 | "unselectable", 74 | "size", 75 | "autoFocus", 76 | "placeholder", 77 | ].forEach(prop => (inputProps[prop] = this.props[prop])); 78 | return ( 79 | (this.input = ref)} 81 | onChange={e => this.callEventHandler(e, "onChange")} 82 | onFocus={e => this.callEventHandler(e, "onFocus")} 83 | onBlur={e => this.callEventHandler(e, "onBlur")} 84 | onKeyPress={e => this.callEventHandler(e, "onKeyPress")} 85 | onKeyUp={e => this.callEventHandler(e, "onKeyUp")} 86 | onKeyDown={e => this.callEventHandler(e, "onKeyDown")} 87 | {...inputProps} 88 | /> 89 | ); 90 | } 91 | } 92 | 93 | ReactNumeric.propTypes = { 94 | type: PropTypes.oneOf(["text", "tel", "hidden"]), 95 | id: PropTypes.string, 96 | className: PropTypes.string, 97 | style: PropTypes.object, 98 | disabled: PropTypes.bool, 99 | name: PropTypes.string, 100 | tabIndex: PropTypes.number, 101 | unselectable: PropTypes.bool, 102 | size: PropTypes.number, 103 | autoFocus: PropTypes.bool, 104 | placeholder: PropTypes.string, 105 | value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), 106 | onChange: PropTypes.func, 107 | onFocus: PropTypes.func, 108 | onBlur: PropTypes.func, 109 | onKeyPress: PropTypes.func, 110 | onKeyUp: PropTypes.func, 111 | onKeyDown: PropTypes.func, 112 | allowDecimalPadding: PropTypes.bool, 113 | caretPositionOnFocus: PropTypes.number, 114 | createLocalList: PropTypes.bool, 115 | currencySymbol: PropTypes.string, 116 | currencySymbolPlacement: PropTypes.string, 117 | decimalCharacter: PropTypes.string, 118 | decimalCharacterAlternative: PropTypes.string, 119 | decimalPlaces: PropTypes.number, 120 | decimalPlacesRawValue: PropTypes.number, 121 | decimalPlacesShownOnBlur: PropTypes.number, 122 | decimalPlacesShownOnFocus: PropTypes.number, 123 | defaultValueOverride: PropTypes.string, 124 | digitalGroupSpacing: PropTypes.string, 125 | digitGroupSeparator: PropTypes.string, 126 | divisorWhenUnfocused: PropTypes.number, 127 | emptyInputBehavior: PropTypes.oneOf(["null", "focus", "press", "always", "zero"]), 128 | eventBubbles: PropTypes.bool, 129 | eventIsCancelable: PropTypes.bool, 130 | failOnUnknownOption: PropTypes.bool, 131 | formatOnPageLoad: PropTypes.bool, 132 | historySize: PropTypes.number, 133 | isCancellable: PropTypes.bool, 134 | leadingZero: PropTypes.oneOf(["allow", "deny", "keep"]), 135 | maximumValue: PropTypes.string, 136 | minimumValue: PropTypes.string, 137 | modifyValueOnWheel: PropTypes.bool, 138 | negativeBracketsTypeOnBlur: PropTypes.string, 139 | negativePositiveSignPlacement: PropTypes.oneOf(["l", "r", "p", "s"]), 140 | negativeSignCharacter: PropTypes.string, 141 | noEventListeners: PropTypes.bool, 142 | onInvalidPaste: PropTypes.oneOf(["error", "ignore", "clamp", "truncate", "replace"]), 143 | outputFormat: PropTypes.oneOf(["string", "number"]), 144 | overrideMinMaxLimits: PropTypes.oneOf(["ceiling", "floor", "ignore"]), 145 | positiveSignCharacter: PropTypes.string, 146 | rawValueDivisor: PropTypes.number, 147 | readOnly: PropTypes.bool, 148 | roundingMethod: PropTypes.string, 149 | saveValueToSessionStorage: PropTypes.bool, 150 | selectNumberOnly: PropTypes.bool, 151 | selectOnFocus: PropTypes.bool, 152 | serializeSpaces: PropTypes.string, 153 | showOnlyNumbersOnFocus: PropTypes.bool, 154 | showPositiveSign: PropTypes.bool, 155 | showWarnings: PropTypes.bool, 156 | styleRules: PropTypes.object, 157 | suffixText: PropTypes.string, 158 | symbolWhenUnfocused: PropTypes.string, 159 | unformatOnHover: PropTypes.bool, 160 | unformatOnSubmit: PropTypes.bool, 161 | valuesToStrings: PropTypes.object, 162 | wheelOn: PropTypes.oneOf(["focus", "hover"]), 163 | wheelStep: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), 164 | preDefined: PropTypes.object, 165 | }; 166 | 167 | ReactNumeric.defaultProps = { 168 | type: "text", 169 | outputFormat: "number", 170 | preDefined: {}, 171 | className: "asdf", 172 | }; 173 | 174 | export const predefinedOptions = AutoNumeric.getPredefinedOptions(); 175 | --------------------------------------------------------------------------------