Skip to content

Commit 078aaa1

Browse files
committed
feat: initial commit
1 parent b0717ac commit 078aaa1

File tree

10 files changed

+432
-22
lines changed

10 files changed

+432
-22
lines changed

.flowconfig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
[ignore]
2-
<PROJECT_ROOT>/lib/.*
32
<PROJECT_ROOT>/node_modules/fbjs/.*
43
<PROJECT_ROOT>/node_modules/.*/tests?/.*\.json
54

README.md

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,53 @@
55
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
66
[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
77

8-
a customized redux-form Field for entering numbers
8+
A customized `redux-form` `Field` for entering numbers. It isn't contrary; it won't stop you from typing, pasting, or cutting
9+
any characters.
10+
When it loses focus it will normalize its value to a number, if valid; otherwise it will trim its value but leave it as a string,
11+
and produce a "must be a number" validation error.
912

1013
## Usage
1114

1215
```sh
1316
npm install --save redux-form-numeric-field
1417
```
1518

19+
```js
20+
const {NumericField} = require('redux-form-numeric-field')
21+
```
22+
or
23+
```js
24+
const {NumericField} = require('redux-form-numeric-field/immutable')
25+
```
26+
27+
## Example
28+
29+
The following field will trim its text when it loses focus:
30+
```js
31+
<NumericField
32+
name="name"
33+
component={YourInputComponent}
34+
/>
35+
```
36+
37+
## API
38+
39+
### `NumericField`
40+
41+
Has the same API as `redux-form`'s `Field`, but normalizes its value to a number when it loses focus
42+
(unless the text is not a valid number, in which case it will just trim the text when it loses focus).
43+
44+
#### `normalizeNumber?: (value: ?(string | number)) => ?(string | number)`
45+
46+
Allows you to override the default implementation which is called on blur. If `value` is a `number` or
47+
correctly-formatted `string`, return a `number`; otherwise, return a `string` or `null`.
48+
49+
#### `normalizeOnBlur?: (value: ?(string | number)) => ?(string | number)`
50+
51+
If you provide this, it will be called with the output of `normalizeNumber`.
52+
53+
#### `validate?: Validator | Array<Validator>`
54+
55+
Unlike a normal `Field`, `NumericField` will call your validators with the normalized number from
56+
`normalizeNumber`. If its value is an invalid number but not whitespace, it will produce a
57+
"must be a number" validation error without calling your own validators.

immutable.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// @flow
2+
3+
module.exports = require('./lib/immutable')

package.json

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@
4444
"url": "https://github.com/jcoreio/redux-form-numeric-field.git"
4545
},
4646
"keywords": [
47-
"es2015",
48-
"react",
49-
"skeleton"
47+
"redux-form",
48+
"formatted-input",
49+
"numeric-input"
5050
],
5151
"author": "Andy Edwards",
5252
"license": "MIT",
@@ -86,6 +86,7 @@
8686
"flow-copy-source": "^1.2.1",
8787
"flow-watch": "^1.1.0",
8888
"husky": "^0.14.3",
89+
"immutable": "^3.8.2",
8990
"istanbul": "^0.4.5",
9091
"jsdom": "^11.5.1",
9192
"jsdom-global": "^3.0.2",
@@ -94,14 +95,19 @@
9495
"react": "^16.2.0",
9596
"react-dom": "^16.2.0",
9697
"react-hot-loader": "^3.0.0-beta.2",
98+
"react-redux": "^5.0.6",
99+
"redux": "^3.7.2",
100+
"redux-form": "^7.2.0",
97101
"rimraf": "^2.6.0",
98102
"semantic-release": "^11.0.0",
99103
"validate-commit-msg": "^2.8.2"
100104
},
101105
"peerDependencies": {
102-
"react": "^15.0.0 || ^16.0.0"
106+
"react": "^15.0.0 || ^16.0.0",
107+
"redux-form": "^7.0.0"
103108
},
104109
"dependencies": {
105-
"prop-types": "^15.0.0"
110+
"prop-types": "^15.0.0",
111+
"redux-form-normalize-on-blur": "^1.0.0"
106112
}
107-
}
113+
}

src/.eslintrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"env": {
3-
"es6": true
3+
"es6": true,
4+
"commonjs": true
45
}
56
}

src/createNumericField.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// @flow
2+
3+
import * as React from 'react'
4+
5+
type NumberNormalizer = (value: ?(string | number)) => ?(string | number)
6+
type Validator = (value: any, allValues: Object, props: Object) => ?any
7+
const WHITESPACE = /^\s*$/
8+
9+
function createNumericField<P: {validate?: Validator | Array<Validator>, normalizeOnBlur?: Function}>(
10+
Field: React.ComponentType<P>
11+
): React.ComponentType<P & {normalizeNumber?: NumberNormalizer}> {
12+
type Props = React.ElementProps<typeof Field> & {normalizeNumber?: NumberNormalizer}
13+
14+
function defaultNormalize(value: ?(string | number)): ?(string | number) {
15+
if (value == null || typeof value === 'number' || WHITESPACE.test(value)) {
16+
return typeof value === 'string' ? value.trim() : value
17+
}
18+
const parsed = Number(value)
19+
return Number.isFinite(parsed) ? parsed : value.trim()
20+
}
21+
22+
return class NumericField extends React.Component<Props> {
23+
normalizeOnBlur = (value: any): any => {
24+
const {normalizeOnBlur} = this.props
25+
const normalizeNumber = this.props.normalizeNumber || defaultNormalize
26+
const result = normalizeNumber(value)
27+
return normalizeOnBlur ? normalizeOnBlur(result) : result
28+
}
29+
30+
validate = (value: any, allValues: Object, props: Object): ?string => {
31+
const normalizeNumber = this.props.normalizeNumber || defaultNormalize
32+
const normalized = normalizeNumber(value)
33+
if (typeof normalized === 'string') {
34+
if (WHITESPACE.test(normalized)) return
35+
return 'must be a number'
36+
}
37+
const {validate} = this.props
38+
if (Array.isArray(validate)) {
39+
for (let validator of validate) {
40+
const result = validator(normalized, allValues, props)
41+
if (result) return result
42+
}
43+
} else if (validate) {
44+
return validate(normalized, allValues, props)
45+
}
46+
}
47+
48+
render(): React.Node {
49+
const {
50+
normalizeNumber, // eslint-disable-line no-unused-vars
51+
...props
52+
} = this.props
53+
return (
54+
<Field
55+
{...props}
56+
validate={this.validate}
57+
normalizeOnBlur={this.normalizeOnBlur}
58+
/>
59+
)
60+
}
61+
}
62+
}
63+
64+
module.exports = createNumericField

src/immutable.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/* @flow */
2+
3+
import {Field as _Field} from 'redux-form-normalize-on-blur/immutable'
4+
import createNumericField from './createNumericField'
5+
6+
const NumericField = createNumericField(_Field)
7+
8+
export {NumericField, createNumericField}
9+

src/index.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/* @flow */
22

3-
import * as React from 'react'
3+
import {Field as _Field} from 'redux-form-normalize-on-blur'
4+
import createNumericField from './createNumericField'
45

5-
const Hello = () => <div>Hello world!</div>
6+
const NumericField = createNumericField(_Field)
67

7-
export default Hello
8+
export {NumericField, createNumericField}

0 commit comments

Comments
 (0)