From b64206c1fae1b4ab86e6e3c3865e6e185692abb6 Mon Sep 17 00:00:00 2001 From: Nikhil Varma Date: Sun, 7 Nov 2021 15:08:13 +0530 Subject: [PATCH 1/4] feat: Add source details in onValueChange --- src/number_format.js | 27 +++++++++++++++++++---- test/library/input_numeric_format.spec.js | 1 + 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/number_format.js b/src/number_format.js index 03ab78b3..20af6e38 100644 --- a/src/number_format.js +++ b/src/number_format.js @@ -128,7 +128,13 @@ class NumberFormat extends React.Component { //set state always when not in focus and formatted value is changed (focusedElm === null && formattedValue !== stateValue) ) { - this.updateValue({ formattedValue, numAsString, input: focusedElm }); + this.updateValue({ + formattedValue, + numAsString, + input: focusedElm, + source: 'prop', + event: null, + }); } } } @@ -723,10 +729,12 @@ class NumberFormat extends React.Component { numAsString: string, inputValue: string, input: HTMLInputElement, + event: SyntheticInputEvent, + source: string, caretPos: number, setCaretPosition: Boolean, }) { - const { formattedValue, input, setCaretPosition = true } = params; + const { formattedValue, input, setCaretPosition = true, source, event } = params; let { numAsString, caretPos } = params; const { onValueChange } = this.props; const { value: lastValue } = this.state; @@ -772,7 +780,7 @@ class NumberFormat extends React.Component { this.setState({ value: formattedValue, numAsString }); // trigger onValueChange synchronously, so parent is updated along with the number format. Fix for #277, #287 - onValueChange(this.getValueObject(formattedValue, numAsString)); + onValueChange(this.getValueObject(formattedValue, numAsString), { event, source }); } } @@ -797,7 +805,14 @@ class NumberFormat extends React.Component { formattedValue = lastValue; } - this.updateValue({ formattedValue, numAsString, inputValue, input: el }); + this.updateValue({ + formattedValue, + numAsString, + inputValue, + input: el, + event: e, + source: 'event', + }); if (isChangeAllowed) { props.onChange(e); @@ -834,6 +849,8 @@ class NumberFormat extends React.Component { numAsString, input: e.target, setCaretPosition: false, + event: e, + source: 'event', }); onBlur(e); return; @@ -900,6 +917,8 @@ class NumberFormat extends React.Component { formattedValue: newValue, caretPos: newCaretPosition, input: el, + event: e, + source: 'event', }); } else if (!negativeRegex.test(value[expectedCaretPosition])) { while (!numRegex.test(value[newCaretPosition - 1]) && newCaretPosition > leftBound) { diff --git a/test/library/input_numeric_format.spec.js b/test/library/input_numeric_format.spec.js index 3dc13eea..671d3c7f 100644 --- a/test/library/input_numeric_format.spec.js +++ b/test/library/input_numeric_format.spec.js @@ -658,6 +658,7 @@ describe('Test NumberFormat as input with numeric format options', () => { expect(wrapper.find('input').prop('value')).toEqual('0.0000001'); }); + describe('Test thousand group style', () => { it('should format on english style thousand grouping', () => { const wrapper = shallow(); From c588ab368da928d09fe94980cc554acc5377a194 Mon Sep 17 00:00:00 2001 From: Nikhil Varma Date: Mon, 8 Nov 2021 22:35:52 +0530 Subject: [PATCH 2/4] feat: Add onValueChange types - Format --- test/library/input_numeric_format.spec.js | 1 - typings/number_format.d.ts | 7 ++++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/test/library/input_numeric_format.spec.js b/test/library/input_numeric_format.spec.js index 671d3c7f..3dc13eea 100644 --- a/test/library/input_numeric_format.spec.js +++ b/test/library/input_numeric_format.spec.js @@ -658,7 +658,6 @@ describe('Test NumberFormat as input with numeric format options', () => { expect(wrapper.find('input').prop('value')).toEqual('0.0000001'); }); - describe('Test thousand group style', () => { it('should format on english style thousand grouping', () => { const wrapper = shallow(); diff --git a/typings/number_format.d.ts b/typings/number_format.d.ts index b6ca4ab1..c18dd49e 100755 --- a/typings/number_format.d.ts +++ b/typings/number_format.d.ts @@ -16,6 +16,11 @@ declare module 'react-number-format' { value: string; } + export interface SourceInfo { + event: SyntheticInputEvent; + source: 'prop' | 'event'; + } + export type FormatInputValueFunction = (inputValue: string) => string; export interface SyntheticInputEvent extends React.SyntheticEvent { @@ -42,7 +47,7 @@ declare module 'react-number-format' { allowNegative?: boolean; allowEmptyFormatting?: boolean; allowLeadingZeros?: boolean; - onValueChange?: (values: NumberFormatValues) => void; + onValueChange?: (values: NumberFormatValues, sourceInfo?: SourceInfo) => void; /** * these are already included in React.HTMLAttributes * onKeyDown: Function; From 6525e7ce22fae9fcd27c1d85d8677779da50a71a Mon Sep 17 00:00:00 2001 From: Nikhil Varma Date: Mon, 8 Nov 2021 23:05:58 +0530 Subject: [PATCH 3/4] feat: Add test cases for onValueChange API change --- test/library/input.spec.js | 19 +++++++++++++++++++ typings/number_format.d.ts | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/test/library/input.spec.js b/test/library/input.spec.js index d9699e82..186bda9f 100644 --- a/test/library/input.spec.js +++ b/test/library/input.spec.js @@ -412,6 +412,25 @@ describe('NumberFormat as input', () => { }); }); + it('should call onValueChange with the right source information', () => { + const spy = jasmine.createSpy(); + const wrapper = shallow(); + + // Test prop change onValueChange + wrapper.setProps({ thousandSeparator: true }); + expect(spy.calls.argsFor(0)[1]).toEqual({ + event: null, + source: 'prop', + }); + + // Test with input change by simulateKeyInput + simulateKeyInput(wrapper.find('input'), '5', 0); + const { event, source } = spy.calls.argsFor(1)[1]; + const { key } = event; + expect(key).toEqual('5'); + expect(source).toEqual('event'); + }); + it('should treat Infinity value as empty string', () => { const wrapper = shallow(); expect(wrapper.state().value).toEqual(''); diff --git a/typings/number_format.d.ts b/typings/number_format.d.ts index c18dd49e..82fa38a4 100755 --- a/typings/number_format.d.ts +++ b/typings/number_format.d.ts @@ -47,7 +47,7 @@ declare module 'react-number-format' { allowNegative?: boolean; allowEmptyFormatting?: boolean; allowLeadingZeros?: boolean; - onValueChange?: (values: NumberFormatValues, sourceInfo?: SourceInfo) => void; + onValueChange?: (values: NumberFormatValues, sourceInfo: SourceInfo) => void; /** * these are already included in React.HTMLAttributes * onKeyDown: Function; From 2ac3cbca9de83639ada2b3660fd8051cd33b8f8c Mon Sep 17 00:00:00 2001 From: Nikhil Varma Date: Mon, 8 Nov 2021 23:13:52 +0530 Subject: [PATCH 4/4] chore: Add documentation --- README.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3dc5d5df..69b39ed6 100755 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ In typescript you also have to enable `"esModuleInterop": true` in your tsconfig | removeFormatting | (formattedValue) => numericString | none | If you are providing custom format method and it add numbers as format you will need to add custom removeFormatting logic. [Demo](https://jinno.io/app/23/removeFormatting?source=react-number-format&displayType=input) | | mask | String (ex : \_) | `' '` | If mask defined, component will show non entered placed with masked value. [Demo](https://jinno.io/app/23/mask?source=react-number-format&displayType=input&format=###-####&mask=_) | | customInput | Component Reference | input | This allow supporting custom inputs with number format. | -| onValueChange | (values) => {} | none | onValueChange handler accepts [values object](#values-object). [Demo](https://jinno.io/app/23/onValueChange?source=react-number-format&displayType=input) | +| onValueChange | (values, sourceInfo) => {} | none | onValueChange handler accepts [values object](#values-object). [Demo](https://jinno.io/app/23/onValueChange?source=react-number-format&displayType=input) | | isAllowed | ([values](#values-object)) => true or false | none | A checker function to check if input value is valid or not. If this function returns false, the onChange method will not get triggered. [Demo](https://jinno.io/app/23/isAllowed?source=react-number-format&displayType=input) | | renderText | (formattedValue, customProps) => React Element | null | A renderText method useful if you want to render formattedValue in different element other than span. It also returns the custom props that are added to the component which can allow passing down props to the rendered element. [Demo](https://jinno.io/app/23/renderText?source=react-number-format&displayType=input) | | getInputRef | (elm) => void | null | Method to get reference of input, span (based on displayType prop) or the customInput's reference. See [Getting reference](#getting-reference). [Demo](https://jinno.io/app/23/getInputRef?source=react-number-format&displayType=input) | @@ -109,7 +109,7 @@ Its recommended to use formattedValue / value / floatValue based on the initial 6. Its recommended to use formattedValue / value / floatValue based on the initial state (it should be same as the initial state format) which you are passing as value prop. If you are saving the `value` key on state make sure to pass isNumericString prop to true. -7. onValueChange is not same as onChange. It gets called on whenever there is change in value which can be caused by any event like change or blur event or by a prop change. It no longer receives event object as second parameter. +7. onValueChange is not same as onChange. It gets called on whenever there is change in value which can be caused by any event like change or blur event or by a prop change. It also provides a second argument which contains the event object and the reason for this function trigger. ### Examples @@ -190,6 +190,21 @@ Output: ¥1,2345,6789 /> ``` +#### Accessing event and the source for onValueChangeTrigger + +```jsx + { + const { formattedValue, value } = values; + // Event is a Synthetic Event wrapper which holds target and other information. Source tells whether the reason for this function being triggered was an 'event' or due to a 'prop' change + const { event, source } = sourceInfo; + }} +/> +``` + #### Format with pattern : Format credit card in an input. [Demo](https://jinno.io/app/23/?source=react-number-format&value=4111111111111111&displayType=input&format=%23%23%23%23%20%23%23%23%23%20%23%23%23%23%20%23%23%23%23) ```jsx