currency-fomatter 1.3.2 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +558 -35
  2. package/dist/cjs/components/currency/hooks.d.ts +52 -0
  3. package/dist/cjs/components/currency/hooks.js +130 -0
  4. package/dist/cjs/components/currency/hooks.js.map +1 -0
  5. package/dist/cjs/components/currency/index.d.ts +44 -107
  6. package/dist/cjs/components/currency/index.js +509 -505
  7. package/dist/cjs/components/currency/index.js.map +1 -1
  8. package/dist/cjs/components/currency/locales.d.ts +55 -0
  9. package/dist/cjs/components/currency/locales.js +382 -0
  10. package/dist/cjs/components/currency/locales.js.map +1 -0
  11. package/dist/cjs/components/currency/utils.d.ts +108 -20
  12. package/dist/cjs/components/currency/utils.js +344 -70
  13. package/dist/cjs/components/currency/utils.js.map +1 -1
  14. package/dist/cjs/components/test/index.d.ts +3 -6
  15. package/dist/cjs/components/test/index.js +121 -15
  16. package/dist/cjs/components/test/index.js.map +1 -1
  17. package/dist/cjs/index.d.ts +4 -2
  18. package/dist/cjs/index.js +19 -2
  19. package/dist/cjs/index.js.map +1 -1
  20. package/dist/esm/components/currency/hooks.d.ts +52 -0
  21. package/dist/esm/components/currency/hooks.js +126 -0
  22. package/dist/esm/components/currency/hooks.js.map +1 -0
  23. package/dist/esm/components/currency/index.d.ts +44 -107
  24. package/dist/esm/components/currency/index.js +497 -508
  25. package/dist/esm/components/currency/index.js.map +1 -1
  26. package/dist/esm/components/currency/locales.d.ts +55 -0
  27. package/dist/esm/components/currency/locales.js +370 -0
  28. package/dist/esm/components/currency/locales.js.map +1 -0
  29. package/dist/esm/components/currency/utils.d.ts +108 -20
  30. package/dist/esm/components/currency/utils.js +338 -66
  31. package/dist/esm/components/currency/utils.js.map +1 -1
  32. package/dist/esm/components/test/index.d.ts +3 -6
  33. package/dist/esm/components/test/index.js +123 -16
  34. package/dist/esm/components/test/index.js.map +1 -1
  35. package/dist/esm/index.d.ts +4 -2
  36. package/dist/esm/index.js +13 -2
  37. package/dist/esm/index.js.map +1 -1
  38. package/package.json +2 -3
@@ -1,144 +1,95 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.unregisterLocale = exports.registerLocale = exports.formatWithIntl = exports.getAutoLocaleConfig = exports.createLocaleConfig = exports.getCompactLabels = exports.detectLocaleFormat = exports.getFormatOptionsFromLocale = exports.getLocaleConfig = exports.localePresets = exports.useCurrencyFormat = exports.defaultCompactDisplay = exports.parseCompact = exports.formatCompact = exports.parseCurrency = exports.formatCurrency = void 0;
3
4
  var tslib_1 = require("tslib");
4
- //@flow
5
- var prop_types_1 = tslib_1.__importDefault(require("prop-types"));
6
5
  var react_1 = tslib_1.__importStar(require("react"));
7
6
  var utils_1 = require("./utils");
8
- var propTypes = {
9
- thousandSeparator: prop_types_1.default.oneOfType([prop_types_1.default.string, prop_types_1.default.oneOf([true])]),
10
- thousandSpacing: prop_types_1.default.oneOf(["2", "2s", "3", "4"]),
11
- decimalSeparator: prop_types_1.default.string,
12
- decimalScale: prop_types_1.default.number,
13
- fixedDecimalScale: prop_types_1.default.bool,
14
- displayType: prop_types_1.default.oneOf(["input", "text"]),
15
- prefix: prop_types_1.default.string,
16
- suffix: prop_types_1.default.string,
17
- format: prop_types_1.default.oneOfType([prop_types_1.default.string, prop_types_1.default.func]),
18
- removeFormatting: prop_types_1.default.func,
19
- mask: prop_types_1.default.oneOfType([prop_types_1.default.string, prop_types_1.default.arrayOf(prop_types_1.default.string)]),
20
- value: prop_types_1.default.oneOfType([prop_types_1.default.number, prop_types_1.default.string]),
21
- isNumericString: prop_types_1.default.bool,
22
- customInput: prop_types_1.default.func,
23
- allowNegative: prop_types_1.default.bool,
24
- onValueChange: prop_types_1.default.func,
25
- onKeyDown: prop_types_1.default.func,
26
- onMouseUp: prop_types_1.default.func,
27
- onChange: prop_types_1.default.func,
28
- onFocus: prop_types_1.default.func,
29
- onBlur: prop_types_1.default.func,
30
- type: prop_types_1.default.oneOf(["text", "tel"]),
31
- isAllowed: prop_types_1.default.func,
32
- renderText: prop_types_1.default.func,
33
- className: prop_types_1.default.string,
34
- placeholder: prop_types_1.default.string
35
- };
36
- var CurrencyFormat = /** @class */ (function (_super) {
37
- tslib_1.__extends(CurrencyFormat, _super);
38
- function CurrencyFormat(props) {
39
- var _this = _super.call(this, props) || this;
40
- //validate props
41
- _this.validateProps();
42
- var formattedValue = _this.formatValueProp();
43
- _this.state = {
44
- value: formattedValue,
45
- numAsString: _this.removeFormatting(formattedValue),
46
- };
47
- _this.onChange = _this.onChange.bind(_this);
48
- _this.onKeyDown = _this.onKeyDown.bind(_this);
49
- _this.onMouseUp = _this.onMouseUp.bind(_this);
50
- _this.onFocus = _this.onFocus.bind(_this);
51
- _this.onBlur = _this.onBlur.bind(_this);
52
- return _this;
53
- }
54
- CurrencyFormat.prototype.componentDidUpdate = function (prevProps) {
55
- this.updateValueIfRequired(prevProps);
56
- };
57
- CurrencyFormat.prototype.updateValueIfRequired = function (prevProps) {
58
- var _a = this, props = _a.props, state = _a.state;
59
- if (prevProps !== props) {
60
- //validate props
61
- this.validateProps();
62
- var stateValue = state.value;
63
- var lastNumStr = state.numAsString || "";
64
- var formattedValue = props.value === undefined ? this.formatNumString(lastNumStr) : this.formatValueProp();
65
- if (formattedValue !== stateValue) {
66
- this.setState({
67
- value: formattedValue,
68
- numAsString: this.removeFormatting(formattedValue),
69
- });
70
- }
71
- }
72
- };
73
- /** Misc methods **/
74
- CurrencyFormat.prototype.getFloatString = function (num) {
75
- if (num === void 0) { num = ""; }
76
- var decimalSeparator = this.getSeparators().decimalSeparator;
77
- var numRegex = this.getNumberRegex(true);
78
- //remove negation for regex check
79
- var hasNegation = num[0] === "-";
80
- if (hasNegation)
81
- num = num.replace("-", "");
82
- num = (num.match(numRegex) || []).join("").replace(decimalSeparator, ".");
83
- //remove extra decimals
84
- var firstDecimalIndex = num.indexOf(".");
85
- if (firstDecimalIndex !== -1) {
86
- num = "".concat(num.substring(0, firstDecimalIndex), ".").concat(num
87
- .substring(firstDecimalIndex + 1, num.length)
88
- .replace(new RegExp((0, utils_1.escapeRegExp)(decimalSeparator), "g"), ""));
89
- }
90
- //add negation back
91
- if (hasNegation)
92
- num = "-" + num;
93
- return num;
94
- };
95
- //returned regex assumes decimalSeparator is as per prop
96
- CurrencyFormat.prototype.getNumberRegex = function (g, ignoreDecimalSeparator) {
97
- var _a = this.props, format = _a.format, decimalScale = _a.decimalScale;
98
- var decimalSeparator = this.getSeparators().decimalSeparator;
99
- return new RegExp("\\d" +
100
- (decimalSeparator && decimalScale !== 0 && !ignoreDecimalSeparator && !format
101
- ? "|" + (0, utils_1.escapeRegExp)(decimalSeparator)
102
- : ""), g ? "g" : undefined);
103
- };
104
- CurrencyFormat.prototype.getSeparators = function () {
105
- var _a = this.props, decimalSeparator = _a.decimalSeparator, _b = _a.thousandSpacing, thousandSpacing = _b === void 0 ? "3" : _b;
106
- var thousandSeparator = this.props.thousandSeparator;
107
- if (thousandSeparator === true) {
108
- thousandSeparator = ",";
7
+ var utils_2 = require("./utils");
8
+ Object.defineProperty(exports, "formatCurrency", { enumerable: true, get: function () { return utils_2.formatCurrency; } });
9
+ Object.defineProperty(exports, "parseCurrency", { enumerable: true, get: function () { return utils_2.parseCurrency; } });
10
+ Object.defineProperty(exports, "formatCompact", { enumerable: true, get: function () { return utils_2.formatCompact; } });
11
+ Object.defineProperty(exports, "parseCompact", { enumerable: true, get: function () { return utils_2.parseCompact; } });
12
+ Object.defineProperty(exports, "defaultCompactDisplay", { enumerable: true, get: function () { return utils_2.defaultCompactDisplay; } });
13
+ // Re-export hooks
14
+ var hooks_1 = require("./hooks");
15
+ Object.defineProperty(exports, "useCurrencyFormat", { enumerable: true, get: function () { return hooks_1.useCurrencyFormat; } });
16
+ // Re-export locales
17
+ var locales_1 = require("./locales");
18
+ Object.defineProperty(exports, "localePresets", { enumerable: true, get: function () { return locales_1.localePresets; } });
19
+ Object.defineProperty(exports, "getLocaleConfig", { enumerable: true, get: function () { return locales_1.getLocaleConfig; } });
20
+ Object.defineProperty(exports, "getFormatOptionsFromLocale", { enumerable: true, get: function () { return locales_1.getFormatOptionsFromLocale; } });
21
+ // Dynamic locale detection
22
+ Object.defineProperty(exports, "detectLocaleFormat", { enumerable: true, get: function () { return locales_1.detectLocaleFormat; } });
23
+ Object.defineProperty(exports, "getCompactLabels", { enumerable: true, get: function () { return locales_1.getCompactLabels; } });
24
+ Object.defineProperty(exports, "createLocaleConfig", { enumerable: true, get: function () { return locales_1.createLocaleConfig; } });
25
+ Object.defineProperty(exports, "getAutoLocaleConfig", { enumerable: true, get: function () { return locales_1.getAutoLocaleConfig; } });
26
+ Object.defineProperty(exports, "formatWithIntl", { enumerable: true, get: function () { return locales_1.formatWithIntl; } });
27
+ // Custom locale registry
28
+ Object.defineProperty(exports, "registerLocale", { enumerable: true, get: function () { return locales_1.registerLocale; } });
29
+ Object.defineProperty(exports, "unregisterLocale", { enumerable: true, get: function () { return locales_1.unregisterLocale; } });
30
+ // Props keys to omit when passing to DOM
31
+ var PROPS_TO_OMIT = [
32
+ "value",
33
+ "format",
34
+ "decimalScale",
35
+ "decimalSeparator",
36
+ "thousandSpacing",
37
+ "thousandSeparator",
38
+ "mask",
39
+ "allowNegative",
40
+ "prefix",
41
+ "suffix",
42
+ "removeFormatting",
43
+ "fixedDecimalScale",
44
+ "isNumericString",
45
+ "isAllowed",
46
+ "onValueChange",
47
+ "onChange",
48
+ "onKeyDown",
49
+ "onMouseUp",
50
+ "onFocus",
51
+ "onBlur",
52
+ "type",
53
+ "displayType",
54
+ "customInput",
55
+ "renderText",
56
+ "getInputRef",
57
+ ];
58
+ var CurrencyFormat = (0, react_1.forwardRef)(function (props, ref) {
59
+ var _a = props.displayType, displayType = _a === void 0 ? "input" : _a, _b = props.decimalSeparator, decimalSeparator = _b === void 0 ? "." : _b, _c = props.thousandSpacing, thousandSpacing = _c === void 0 ? "3" : _c, _d = props.thousandSeparator, thousandSeparator = _d === void 0 ? "," : _d, _e = props.fixedDecimalScale, fixedDecimalScale = _e === void 0 ? false : _e, _f = props.prefix, prefix = _f === void 0 ? "" : _f, _g = props.suffix, suffix = _g === void 0 ? "" : _g, _h = props.allowNegative, allowNegative = _h === void 0 ? true : _h, _j = props.isNumericString, isNumericStringProp = _j === void 0 ? false : _j, _k = props.type, type = _k === void 0 ? "text" : _k, name = props.name, onValueChange = props.onValueChange, onChangeProp = props.onChange, onKeyDownProp = props.onKeyDown, onMouseUpProp = props.onMouseUp, onFocusProp = props.onFocus, onBlurProp = props.onBlur, isAllowed = props.isAllowed, format = props.format, decimalScale = props.decimalScale, _l = props.mask, mask = _l === void 0 ? " " : _l, removeFormattingProp = props.removeFormatting, valueProp = props.value, customInput = props.customInput, renderText = props.renderText, getInputRef = props.getInputRef, _m = props.className, className = _m === void 0 ? "" : _m, _o = props.placeholder, placeholder = _o === void 0 ? "" : _o, restProps = tslib_1.__rest(props, ["displayType", "decimalSeparator", "thousandSpacing", "thousandSeparator", "fixedDecimalScale", "prefix", "suffix", "allowNegative", "isNumericString", "type", "name", "onValueChange", "onChange", "onKeyDown", "onMouseUp", "onFocus", "onBlur", "isAllowed", "format", "decimalScale", "mask", "removeFormatting", "value", "customInput", "renderText", "getInputRef", "className", "placeholder"]);
60
+ // Refs
61
+ var inputRef = (0, react_1.useRef)(null);
62
+ var prevPropsRef = (0, react_1.useRef)(props);
63
+ // Forward ref
64
+ (0, react_1.useImperativeHandle)(ref, function () { return inputRef.current; });
65
+ // Helper functions using useCallback for memoization
66
+ var getSeparators = (0, react_1.useCallback)(function () {
67
+ var separator = thousandSeparator;
68
+ if (separator === true) {
69
+ separator = ",";
109
70
  }
110
71
  return {
111
72
  decimalSeparator: decimalSeparator,
112
- thousandSeparator: thousandSeparator,
73
+ thousandSeparator: separator,
113
74
  thousandSpacing: thousandSpacing,
114
75
  };
115
- };
116
- CurrencyFormat.prototype.getMaskAtIndex = function (index) {
117
- var _a = this.props.mask, mask = _a === void 0 ? " " : _a;
76
+ }, [decimalSeparator, thousandSeparator, thousandSpacing]);
77
+ var getMaskAtIndex = (0, react_1.useCallback)(function (index) {
118
78
  if (typeof mask === "string") {
119
79
  return mask;
120
80
  }
121
81
  return mask[index] || " ";
122
- };
123
- CurrencyFormat.prototype.validateProps = function () {
124
- var mask = this.props.mask;
125
- //validate decimalSeparator and thousandSeparator
126
- var _a = this.getSeparators(), decimalSeparator = _a.decimalSeparator, thousandSeparator = _a.thousandSeparator;
127
- if (decimalSeparator === thousandSeparator) {
128
- throw new Error("\n Decimal separator can't be same as thousand separator.\n\n thousandSeparator: ".concat(thousandSeparator, " (thousandSeparator = {true} is same as thousandSeparator = \",\")\n decimalSeparator: ").concat(decimalSeparator, " (default value for decimalSeparator is .)\n "));
129
- }
130
- //validate mask
131
- if (mask) {
132
- var maskAsStr = mask === "string" ? mask : mask.toString();
133
- if (maskAsStr.match(/\d/g)) {
134
- throw new Error("\n Mask ".concat(mask, " should not contain numeric character;\n "));
135
- }
136
- }
137
- };
138
- CurrencyFormat.prototype.splitDecimal = function (numStr) {
139
- var allowNegative = this.props.allowNegative;
140
- var hasNagation = numStr[0] === "-";
141
- var addNegation = hasNagation && allowNegative;
82
+ }, [mask]);
83
+ var getNumberRegex = (0, react_1.useCallback)(function (g, ignoreDecimalSeparator) {
84
+ var decSep = getSeparators().decimalSeparator;
85
+ return new RegExp("\\d" +
86
+ (decSep && decimalScale !== 0 && !ignoreDecimalSeparator && !format
87
+ ? "|" + (0, utils_1.escapeRegExp)(decSep)
88
+ : ""), g ? "g" : undefined);
89
+ }, [getSeparators, decimalScale, format]);
90
+ var splitDecimal = (0, react_1.useCallback)(function (numStr) {
91
+ var hasNegation = numStr[0] === "-";
92
+ var addNegation = hasNegation && allowNegative;
142
93
  numStr = numStr.replace("-", "");
143
94
  var parts = numStr.split(".");
144
95
  var beforeDecimal = parts[0];
@@ -146,130 +97,127 @@ var CurrencyFormat = /** @class */ (function (_super) {
146
97
  return {
147
98
  beforeDecimal: beforeDecimal,
148
99
  afterDecimal: afterDecimal,
149
- hasNagation: hasNagation,
100
+ hasNegation: hasNegation,
150
101
  addNegation: addNegation,
151
102
  };
152
- };
153
- /** Misc methods end **/
154
- /** caret specific methods **/
155
- CurrencyFormat.prototype.setPatchedCaretPosition = function (el, caretPos, currentValue) {
156
- /* setting caret position within timeout of 0ms is required for mobile chrome,
157
- otherwise browser resets the caret position after we set it
158
- We are also setting it without timeout so that in normal browser we don't see the flickering */
159
- (0, utils_1.setCaretPosition)(el, caretPos);
160
- setTimeout(function () {
161
- if (el.value === currentValue)
162
- (0, utils_1.setCaretPosition)(el, caretPos);
163
- }, 0);
164
- };
165
- /* This keeps the caret within typing area so people can't type in between prefix or suffix */
166
- CurrencyFormat.prototype.correctCaretPosition = function (value, caretPos, direction) {
167
- var _a = this.props, prefix = _a.prefix, suffix = _a.suffix, format = _a.format;
168
- //in case of format as number limit between prefix and suffix
169
- if (!format) {
170
- var hasNegation = value[0] === "-";
171
- return Math.min(Math.max(caretPos, prefix.length + (hasNegation ? 1 : 0)), value.length - suffix.length);
103
+ }, [allowNegative]);
104
+ var getFloatString = (0, react_1.useCallback)(function (num) {
105
+ if (num === void 0) { num = ""; }
106
+ var decSep = getSeparators().decimalSeparator;
107
+ var numRegex = getNumberRegex(true);
108
+ // Remove negation for regex check
109
+ var hasNegation = num[0] === "-";
110
+ if (hasNegation)
111
+ num = num.replace("-", "");
112
+ num = (num.match(numRegex) || []).join("").replace(decSep, ".");
113
+ // Remove extra decimals
114
+ var firstDecimalIndex = num.indexOf(".");
115
+ if (firstDecimalIndex !== -1) {
116
+ num = "".concat(num.substring(0, firstDecimalIndex), ".").concat(num
117
+ .substring(firstDecimalIndex + 1, num.length)
118
+ .replace(new RegExp((0, utils_1.escapeRegExp)(decSep), "g"), ""));
172
119
  }
173
- //in case if custom format method don't do anything
174
- if (typeof format === "function")
175
- return caretPos;
176
- /* in case format is string find the closest # position from the caret position */
177
- //in case the caretPos have input value on it don't do anything
178
- if (format[caretPos] === "#" && (0, utils_1.charIsNumber)(value[caretPos]))
179
- return caretPos;
180
- //if caretPos is just after input value don't do anything
181
- if (format[caretPos - 1] === "#" && (0, utils_1.charIsNumber)(value[caretPos - 1]))
182
- return caretPos;
183
- //find the nearest caret position
184
- var firstHashPosition = format.indexOf("#");
185
- var lastHashPosition = format.lastIndexOf("#");
186
- //limit the cursor between the first # position and the last # position
187
- caretPos = Math.min(Math.max(caretPos, firstHashPosition), lastHashPosition + 1);
188
- var nextPos = format.substring(caretPos, format.length).indexOf("#");
189
- var caretLeftBound = caretPos;
190
- var caretRightBoud = caretPos + (nextPos === -1 ? 0 : nextPos);
191
- //get the position where the last number is present
192
- while (caretLeftBound > firstHashPosition &&
193
- (format[caretLeftBound] !== "#" || !(0, utils_1.charIsNumber)(value[caretLeftBound]))) {
194
- caretLeftBound -= 1;
195
- }
196
- var goToLeft = !(0, utils_1.charIsNumber)(value[caretRightBoud]) ||
197
- (direction === "left" && caretPos !== firstHashPosition) ||
198
- caretPos - caretLeftBound < caretRightBoud - caretPos;
199
- return goToLeft ? caretLeftBound + 1 : caretRightBoud;
200
- };
201
- CurrencyFormat.prototype.getCaretPosition = function (inputValue, formattedValue, caretPos) {
202
- var format = this.props.format;
203
- var stateValue = this.state.value;
204
- var numRegex = this.getNumberRegex(true);
205
- var inputNumber = (inputValue.match(numRegex) || []).join("");
206
- var formattedNumber = (formattedValue.match(numRegex) || []).join("");
207
- var j, i;
208
- j = 0;
209
- for (i = 0; i < caretPos; i++) {
210
- var currentInputChar = inputValue[i] || "";
211
- var currentFormatChar = formattedValue[j] || "";
212
- //no need to increase new cursor position if formatted value does not have those characters
213
- //case inputValue = 1a23 and formattedValue = 123
214
- if (!currentInputChar.match(numRegex) && currentInputChar !== currentFormatChar)
215
- continue;
216
- //When we are striping out leading zeros maintain the new cursor position
217
- //Case inputValue = 00023 and formattedValue = 23;
218
- if (currentInputChar === "0" &&
219
- currentFormatChar.match(numRegex) &&
220
- currentFormatChar !== "0" &&
221
- inputNumber.length !== formattedNumber.length)
222
- continue;
223
- //we are not using currentFormatChar because j can change here
224
- while (currentInputChar !== formattedValue[j] && j < formattedValue.length)
225
- j++;
226
- j++;
120
+ // Add negation back
121
+ if (hasNegation)
122
+ num = "-" + num;
123
+ return num;
124
+ }, [getSeparators, getNumberRegex]);
125
+ var formatThousand = (0, react_1.useCallback)(function (beforeDecimal, separator, spacing) {
126
+ if (spacing === void 0) { spacing = "3"; }
127
+ var digitalGroup;
128
+ switch (spacing) {
129
+ case utils_1.thousandGroupSpacing.two:
130
+ digitalGroup = /(\d)(?=(\d{2})+(?!\d))/g;
131
+ break;
132
+ case utils_1.thousandGroupSpacing.twoScaled:
133
+ digitalGroup = /(\d)(?=(((\d{2})+)(\d{1})(?!\d)))/g;
134
+ break;
135
+ case utils_1.thousandGroupSpacing.four:
136
+ digitalGroup = /(\d)(?=(\d{4})+(?!\d))/g;
137
+ break;
138
+ default:
139
+ digitalGroup = /(\d)(?=(\d{3})+(?!\d))/g;
227
140
  }
228
- if (typeof format === "string" && !stateValue) {
229
- //set it to the maximum value so it goes after the last number
230
- j = formattedValue.length;
141
+ return beforeDecimal.replace(digitalGroup, "$1" + separator);
142
+ }, []);
143
+ var formatWithPattern = (0, react_1.useCallback)(function (numStr) {
144
+ if (typeof format !== "string")
145
+ return numStr;
146
+ var hashCount = 0;
147
+ var formattedNumberAry = format.split("");
148
+ for (var i = 0, ln = format.length; i < ln; i++) {
149
+ if (format[i] === "#") {
150
+ formattedNumberAry[i] =
151
+ numStr[hashCount] || getMaskAtIndex(hashCount);
152
+ hashCount += 1;
153
+ }
231
154
  }
232
- //correct caret position if its outside of editable area
233
- j = this.correctCaretPosition(formattedValue, j);
234
- return j;
235
- };
236
- /** caret specific methods ends **/
237
- /** methods to remove formattting **/
238
- CurrencyFormat.prototype.removePrefixAndSuffix = function (val) {
239
- var _a = this.props, format = _a.format, prefix = _a.prefix, suffix = _a.suffix;
240
- //remove prefix and suffix
155
+ return formattedNumberAry.join("");
156
+ }, [format, getMaskAtIndex]);
157
+ var formatAsNumber = (0, react_1.useCallback)(function (numStr) {
158
+ var _a = getSeparators(), tSep = _a.thousandSeparator, decSep = _a.decimalSeparator, tSpacing = _a.thousandSpacing;
159
+ var hasDecimalSeparator = numStr.indexOf(".") !== -1 || (decimalScale && fixedDecimalScale);
160
+ var _b = splitDecimal(numStr), beforeDecimal = _b.beforeDecimal, afterDecimal = _b.afterDecimal;
161
+ var addNegation = splitDecimal(numStr).addNegation;
162
+ // Apply decimal precision if defined
163
+ if (decimalScale !== undefined) {
164
+ afterDecimal = (0, utils_1.limitToScale)(afterDecimal, decimalScale, fixedDecimalScale);
165
+ }
166
+ if (tSep) {
167
+ beforeDecimal = formatThousand(beforeDecimal, tSep, tSpacing);
168
+ }
169
+ // Add prefix and suffix
170
+ if (prefix)
171
+ beforeDecimal = prefix + beforeDecimal;
172
+ if (suffix)
173
+ afterDecimal = afterDecimal + suffix;
174
+ // Restore negation sign
175
+ if (addNegation)
176
+ beforeDecimal = "-" + beforeDecimal;
177
+ return (beforeDecimal + ((hasDecimalSeparator && decSep) || "") + afterDecimal);
178
+ }, [
179
+ getSeparators,
180
+ decimalScale,
181
+ fixedDecimalScale,
182
+ splitDecimal,
183
+ formatThousand,
184
+ prefix,
185
+ suffix,
186
+ ]);
187
+ var removePrefixAndSuffix = (0, react_1.useCallback)(function (val) {
241
188
  if (!format && val) {
242
189
  var isNegative = val[0] === "-";
243
- //remove negation sign
190
+ // Remove negation sign
244
191
  if (isNegative)
245
192
  val = val.substring(1, val.length);
246
- //remove prefix
247
- val = prefix && val.indexOf(prefix) === 0 ? val.substring(prefix.length, val.length) : val;
248
- //remove suffix
193
+ // Remove prefix
194
+ val =
195
+ prefix && val.indexOf(prefix) === 0
196
+ ? val.substring(prefix.length, val.length)
197
+ : val;
198
+ // Remove suffix
249
199
  var suffixLastIndex = val.lastIndexOf(suffix);
250
200
  val =
251
- suffix && suffixLastIndex !== -1 && suffixLastIndex === val.length - suffix.length
201
+ suffix &&
202
+ suffixLastIndex !== -1 &&
203
+ suffixLastIndex === val.length - suffix.length
252
204
  ? val.substring(0, suffixLastIndex)
253
205
  : val;
254
- //add negation sign back
206
+ // Add negation sign back
255
207
  if (isNegative)
256
208
  val = "-" + val;
257
209
  }
258
210
  return val;
259
- };
260
- CurrencyFormat.prototype.removePatternFormatting = function (val) {
261
- var format = this.props.format;
211
+ }, [format, prefix, suffix]);
212
+ var removePatternFormatting = (0, react_1.useCallback)(function (val) {
213
+ if (typeof format !== "string")
214
+ return val;
262
215
  var formatArray = format.split("#").filter(function (str) { return str !== ""; });
263
216
  var start = 0;
264
217
  var numStr = "";
265
218
  for (var i = 0, ln = formatArray.length; i <= ln; i++) {
266
219
  var part = formatArray[i] || "";
267
- //if i is the last fragment take the index of end of the value
268
- //For case like +1 (911) 911 91 91 having pattern +1 (###) ### ## ##
269
220
  var index = i === ln ? val.length : val.indexOf(part, start);
270
- /* in any case if we don't find the pattern part in the value assume the val as numeric string
271
- This will be also in case if user has started typing, in any other case it will not be -1
272
- unless wrong prop value is provided */
273
221
  if (index === -1) {
274
222
  numStr = val;
275
223
  break;
@@ -280,194 +228,212 @@ var CurrencyFormat = /** @class */ (function (_super) {
280
228
  }
281
229
  }
282
230
  return (numStr.match(/\d/g) || []).join("");
283
- };
284
- CurrencyFormat.prototype.removeFormatting = function (val) {
285
- var _a = this.props, format = _a.format, removeFormatting = _a.removeFormatting;
231
+ }, [format]);
232
+ var removeFormatting = (0, react_1.useCallback)(function (val) {
286
233
  if (!val)
287
234
  return val;
288
235
  if (!format) {
289
- val = this.removePrefixAndSuffix(val);
290
- val = this.getFloatString(val);
236
+ val = removePrefixAndSuffix(val);
237
+ val = getFloatString(val);
291
238
  }
292
239
  else if (typeof format === "string") {
293
- val = this.removePatternFormatting(val);
240
+ val = removePatternFormatting(val);
294
241
  }
295
- else if (typeof removeFormatting === "function") {
296
- //condition need to be handled if format method is provide,
297
- val = removeFormatting(val);
242
+ else if (typeof removeFormattingProp === "function") {
243
+ val = removeFormattingProp(val);
298
244
  }
299
245
  else {
300
246
  val = (val.match(/\d/g) || []).join("");
301
247
  }
302
248
  return val;
303
- };
304
- /** methods to remove formattting end **/
305
- /*** format specific methods start ***/
306
- /**
307
- * Format when # based string is provided
308
- * @param {string} numStr Numeric String
309
- * @return {string} formatted Value
310
- */
311
- CurrencyFormat.prototype.formatWithPattern = function (numStr) {
312
- var format = this.props.format;
313
- var hashCount = 0;
314
- var formattedNumberAry = format.split("");
315
- for (var i = 0, ln = format.length; i < ln; i++) {
316
- if (format[i] === "#") {
317
- formattedNumberAry[i] = numStr[hashCount] || this.getMaskAtIndex(hashCount);
318
- hashCount += 1;
319
- }
320
- }
321
- return formattedNumberAry.join("");
322
- };
323
- /**
324
- * Format the given string according to thousand separator and thousand spacing
325
- * @param {*} beforeDecimal
326
- * @param {*} thousandSeparator
327
- * @param {*} thousandSpacing
328
- */
329
- CurrencyFormat.prototype.formatThousand = function (beforeDecimal, thousandSeparator, thousandSpacing) {
330
- if (thousandSpacing === void 0) { thousandSpacing = "3"; }
331
- var digitalGroup;
332
- switch (thousandSpacing) {
333
- case utils_1.thousandGroupSpacing.two:
334
- digitalGroup = /(\d)(?=(\d{2})+(?!\d))/g;
335
- break;
336
- case utils_1.thousandGroupSpacing.twoScaled:
337
- digitalGroup = /(\d)(?=(((\d{2})+)(\d{1})(?!\d)))/g;
338
- break;
339
- case utils_1.thousandGroupSpacing.four:
340
- digitalGroup = /(\d)(?=(\d{4})+(?!\d))/g;
341
- break;
342
- default:
343
- digitalGroup = /(\d)(?=(\d{3})+(?!\d))/g;
344
- }
345
- return beforeDecimal.replace(digitalGroup, "$1" + thousandSeparator);
346
- };
347
- /**
348
- * @param {string} numStr Numeric string/floatString] It always have decimalSeparator as .
349
- * @return {string} formatted Value
350
- */
351
- CurrencyFormat.prototype.formatAsNumber = function (numStr) {
352
- var _a = this.props, decimalScale = _a.decimalScale, fixedDecimalScale = _a.fixedDecimalScale, prefix = _a.prefix, suffix = _a.suffix;
353
- var _b = this.getSeparators(), thousandSeparator = _b.thousandSeparator, decimalSeparator = _b.decimalSeparator, _c = _b.thousandSpacing, thousandSpacing = _c === void 0 ? "3" : _c;
354
- var hasDecimalSeparator = numStr.indexOf(".") !== -1 || (decimalScale && fixedDecimalScale);
355
- var _d = this.splitDecimal(numStr), beforeDecimal = _d.beforeDecimal, afterDecimal = _d.afterDecimal, addNegation = _d.addNegation; // eslint-disable-line prefer-const
356
- //apply decimal precision if its defined
357
- if (decimalScale !== undefined)
358
- afterDecimal = (0, utils_1.limitToScale)(afterDecimal, decimalScale, fixedDecimalScale);
359
- if (thousandSeparator) {
360
- beforeDecimal = this.formatThousand(beforeDecimal, thousandSeparator, thousandSpacing);
361
- }
362
- //add prefix and suffix
363
- if (prefix)
364
- beforeDecimal = prefix + beforeDecimal;
365
- if (suffix)
366
- afterDecimal = afterDecimal + suffix;
367
- //restore negation sign
368
- if (addNegation)
369
- beforeDecimal = "-" + beforeDecimal;
370
- numStr = beforeDecimal + ((hasDecimalSeparator && decimalSeparator) || "") + afterDecimal;
371
- return numStr;
372
- };
373
- CurrencyFormat.prototype.formatNumString = function (value) {
249
+ }, [
250
+ format,
251
+ removePrefixAndSuffix,
252
+ getFloatString,
253
+ removePatternFormatting,
254
+ removeFormattingProp,
255
+ ]);
256
+ var formatNumString = (0, react_1.useCallback)(function (value) {
374
257
  if (value === void 0) { value = ""; }
375
- var format = this.props.format;
376
258
  var formattedValue = value;
377
259
  if (value === "") {
378
260
  formattedValue = "";
379
261
  }
380
262
  else if (value === "-" && !format) {
381
263
  formattedValue = "-";
382
- value = "";
383
264
  }
384
265
  else if (typeof format === "string") {
385
- formattedValue = this.formatWithPattern(formattedValue);
266
+ formattedValue = formatWithPattern(formattedValue);
386
267
  }
387
268
  else if (typeof format === "function") {
388
269
  formattedValue = format(formattedValue);
389
270
  }
390
271
  else {
391
- formattedValue = this.formatAsNumber(formattedValue);
272
+ formattedValue = formatAsNumber(formattedValue);
392
273
  }
393
274
  return formattedValue;
394
- };
395
- CurrencyFormat.prototype.formatValueProp = function () {
396
- var _a = this.props, format = _a.format, decimalScale = _a.decimalScale, fixedDecimalScale = _a.fixedDecimalScale;
397
- var _b = this.props, value = _b.value, isNumericString = _b.isNumericString;
398
- // if value is not defined return empty string
275
+ }, [format, formatWithPattern, formatAsNumber]);
276
+ var formatNegation = (0, react_1.useCallback)(function (value) {
277
+ if (value === void 0) { value = ""; }
278
+ var negationRegex = new RegExp("(-)");
279
+ var doubleNegationRegex = new RegExp("(-)(.)*(-)");
280
+ var hasNegation = negationRegex.test(value);
281
+ var removeNegationFlag = doubleNegationRegex.test(value);
282
+ value = value.replace(/-/g, "");
283
+ if (hasNegation && !removeNegationFlag && allowNegative) {
284
+ value = "-" + value;
285
+ }
286
+ return value;
287
+ }, [allowNegative]);
288
+ var formatInput = (0, react_1.useCallback)(function (value) {
289
+ if (value === void 0) { value = ""; }
290
+ if (!format) {
291
+ value = formatNegation(value);
292
+ }
293
+ value = removeFormatting(value);
294
+ return formatNumString(value);
295
+ }, [format, formatNegation, removeFormatting, formatNumString]);
296
+ var formatValueProp = (0, react_1.useCallback)(function () {
297
+ var value = valueProp;
298
+ var isNumericString = isNumericStringProp;
399
299
  if (value === undefined)
400
300
  return "";
401
301
  if (typeof value === "number") {
402
302
  value = value.toString();
403
303
  isNumericString = true;
404
304
  }
405
- //round the number based on decimalScale
406
- //format only if non formatted value is provided
407
305
  if (isNumericString && !format && typeof decimalScale === "number") {
408
306
  value = (0, utils_1.roundToPrecision)(value, decimalScale, fixedDecimalScale);
409
307
  }
410
- var formattedValue = isNumericString ? this.formatNumString(value) : this.formatInput(value);
411
- return formattedValue;
412
- };
413
- CurrencyFormat.prototype.formatNegation = function (value) {
414
- if (value === void 0) { value = ""; }
415
- var allowNegative = this.props.allowNegative;
416
- var negationRegex = new RegExp("(-)");
417
- var doubleNegationRegex = new RegExp("(-)(.)*(-)");
418
- // Check number has '-' value
419
- var hasNegation = negationRegex.test(value);
420
- // Check number has 2 or more '-' values
421
- var removeNegation = doubleNegationRegex.test(value);
422
- //remove negation
423
- value = value.replace(/-/g, "");
424
- if (hasNegation && !removeNegation && allowNegative) {
425
- value = "-" + value;
308
+ return isNumericString
309
+ ? formatNumString(value)
310
+ : formatInput(value);
311
+ }, [
312
+ valueProp,
313
+ isNumericStringProp,
314
+ format,
315
+ decimalScale,
316
+ fixedDecimalScale,
317
+ formatNumString,
318
+ formatInput,
319
+ ]);
320
+ // Validate props
321
+ var validateProps = (0, react_1.useCallback)(function () {
322
+ var _a = getSeparators(), decSep = _a.decimalSeparator, tSep = _a.thousandSeparator;
323
+ if (decSep === tSep) {
324
+ throw new Error("\n Decimal separator can't be same as thousand separator.\n thousandSeparator: ".concat(tSep, " (thousandSeparator = {true} is same as thousandSeparator = \",\")\n decimalSeparator: ").concat(decSep, " (default value for decimalSeparator is .)\n "));
426
325
  }
427
- return value;
428
- };
429
- CurrencyFormat.prototype.formatInput = function (value) {
430
- if (value === void 0) { value = ""; }
431
- var format = this.props.format;
432
- //format negation only if we are formatting as number
326
+ if (mask) {
327
+ var maskAsStr = typeof mask === "string" ? mask : mask.toString();
328
+ if (maskAsStr.match(/\d/g)) {
329
+ throw new Error("Mask ".concat(mask, " should not contain numeric character;"));
330
+ }
331
+ }
332
+ }, [getSeparators, mask]);
333
+ // Initial state calculation
334
+ var getInitialState = (0, react_1.useCallback)(function () {
335
+ var formattedValue = formatValueProp();
336
+ return {
337
+ value: formattedValue,
338
+ numAsString: removeFormatting(formattedValue),
339
+ };
340
+ }, [formatValueProp, removeFormatting]);
341
+ // State
342
+ var _p = (0, react_1.useState)(function () {
343
+ validateProps();
344
+ return getInitialState();
345
+ }), state = _p[0], setState = _p[1];
346
+ // Caret position helpers
347
+ var setPatchedCaretPosition = (0, react_1.useCallback)(function (el, caretPos, currentValue) {
348
+ (0, utils_1.setCaretPosition)(el, caretPos);
349
+ setTimeout(function () {
350
+ if (el.value === currentValue)
351
+ (0, utils_1.setCaretPosition)(el, caretPos);
352
+ }, 0);
353
+ }, []);
354
+ var correctCaretPosition = (0, react_1.useCallback)(function (value, caretPos, direction) {
433
355
  if (!format) {
434
- value = this.formatNegation(value);
435
- }
436
- //remove formatting from number
437
- value = this.removeFormatting(value);
438
- return this.formatNumString(value);
439
- };
440
- /*** format specific methods end ***/
441
- CurrencyFormat.prototype.isCharacterAFormat = function (caretPos, value) {
442
- var _a = this.props, format = _a.format, prefix = _a.prefix, suffix = _a.suffix, decimalScale = _a.decimalScale, fixedDecimalScale = _a.fixedDecimalScale;
443
- var decimalSeparator = this.getSeparators().decimalSeparator;
444
- //check within format pattern
356
+ var hasNegation = value[0] === "-";
357
+ return Math.min(Math.max(caretPos, prefix.length + (hasNegation ? 1 : 0)), value.length - suffix.length);
358
+ }
359
+ if (typeof format === "function")
360
+ return caretPos;
361
+ if (typeof format === "string") {
362
+ if (format[caretPos] === "#" && (0, utils_1.charIsNumber)(value[caretPos])) {
363
+ return caretPos;
364
+ }
365
+ if (format[caretPos - 1] === "#" && (0, utils_1.charIsNumber)(value[caretPos - 1])) {
366
+ return caretPos;
367
+ }
368
+ var firstHashPosition = format.indexOf("#");
369
+ var lastHashPosition = format.lastIndexOf("#");
370
+ caretPos = Math.min(Math.max(caretPos, firstHashPosition), lastHashPosition + 1);
371
+ var nextPos = format.substring(caretPos, format.length).indexOf("#");
372
+ var caretLeftBound = caretPos;
373
+ var caretRightBound = caretPos + (nextPos === -1 ? 0 : nextPos);
374
+ while (caretLeftBound > firstHashPosition &&
375
+ (format[caretLeftBound] !== "#" ||
376
+ !(0, utils_1.charIsNumber)(value[caretLeftBound]))) {
377
+ caretLeftBound -= 1;
378
+ }
379
+ var goToLeft = !(0, utils_1.charIsNumber)(value[caretRightBound]) ||
380
+ (direction === "left" && caretPos !== firstHashPosition) ||
381
+ caretPos - caretLeftBound < caretRightBound - caretPos;
382
+ return goToLeft ? caretLeftBound + 1 : caretRightBound;
383
+ }
384
+ return caretPos;
385
+ }, [format, prefix, suffix]);
386
+ var getCaretPosition = (0, react_1.useCallback)(function (inputValue, formattedValue, caretPos) {
387
+ var numRegex = getNumberRegex(true);
388
+ var inputNumber = (inputValue.match(numRegex) || []).join("");
389
+ var formattedNumber = (formattedValue.match(numRegex) || []).join("");
390
+ var j = 0;
391
+ for (var i = 0; i < caretPos; i++) {
392
+ var currentInputChar = inputValue[i] || "";
393
+ var currentFormatChar = formattedValue[j] || "";
394
+ if (!currentInputChar.match(numRegex) &&
395
+ currentInputChar !== currentFormatChar) {
396
+ continue;
397
+ }
398
+ if (currentInputChar === "0" &&
399
+ currentFormatChar.match(numRegex) &&
400
+ currentFormatChar !== "0" &&
401
+ inputNumber.length !== formattedNumber.length) {
402
+ continue;
403
+ }
404
+ while (currentInputChar !== formattedValue[j] &&
405
+ j < formattedValue.length) {
406
+ j++;
407
+ }
408
+ j++;
409
+ }
410
+ if (typeof format === "string" && !state.value) {
411
+ j = formattedValue.length;
412
+ }
413
+ j = correctCaretPosition(formattedValue, j);
414
+ return j;
415
+ }, [getNumberRegex, format, state.value, correctCaretPosition]);
416
+ var isCharacterAFormat = (0, react_1.useCallback)(function (caretPos, value) {
417
+ var decSep = getSeparators().decimalSeparator;
445
418
  if (typeof format === "string" && format[caretPos] !== "#")
446
419
  return true;
447
- //check in number format
448
420
  if (!format &&
449
421
  (caretPos < prefix.length ||
450
422
  caretPos >= value.length - suffix.length ||
451
- (decimalScale && fixedDecimalScale && value[caretPos] === decimalSeparator))) {
423
+ (decimalScale && fixedDecimalScale && value[caretPos] === decSep))) {
452
424
  return true;
453
425
  }
454
426
  return false;
455
- };
456
- CurrencyFormat.prototype.checkIfFormatGotDeleted = function (start, end, value) {
427
+ }, [format, prefix, suffix, decimalScale, fixedDecimalScale, getSeparators]);
428
+ var checkIfFormatGotDeleted = (0, react_1.useCallback)(function (start, end, value) {
457
429
  for (var i = start; i < end; i++) {
458
- if (this.isCharacterAFormat(i, value))
430
+ if (isCharacterAFormat(i, value))
459
431
  return true;
460
432
  }
461
433
  return false;
462
- };
463
- /**
464
- * This will check if any formatting got removed by the delete or backspace and reset the value
465
- * It will also work as fallback if android chome keyDown handler does not work
466
- **/
467
- CurrencyFormat.prototype.correctInputValue = function (caretPos, lastValue, value) {
468
- var format = this.props.format;
469
- var lastNumStr = this.state.numAsString || "";
470
- //don't do anyhting if something got added, or if value is empty string (when whole input is cleared)
434
+ }, [isCharacterAFormat]);
435
+ var correctInputValue = (0, react_1.useCallback)(function (caretPos, lastValue, value) {
436
+ var lastNumStr = state.numAsString || "";
471
437
  if (value.length >= lastValue.length || !value.length) {
472
438
  return value;
473
439
  }
@@ -477,219 +443,257 @@ var CurrencyFormat = /** @class */ (function (_super) {
477
443
  var deletedIndex = lastValueParts[1].lastIndexOf(newValueParts[1]);
478
444
  var diff = deletedIndex !== -1 ? lastValueParts[1].substring(0, deletedIndex) : "";
479
445
  var end = start + diff.length;
480
- //if format got deleted reset the value to last value
481
- if (this.checkIfFormatGotDeleted(start, end, lastValue)) {
446
+ if (checkIfFormatGotDeleted(start, end, lastValue)) {
482
447
  value = lastValue;
483
448
  }
484
- //for numbers check if beforeDecimal got deleted and there is nothing after decimal,
485
- //clear all numbers in such case while keeping the - sign
486
449
  if (!format) {
487
- var numericString = this.removeFormatting(value);
488
- var _a = this.splitDecimal(numericString), beforeDecimal = _a.beforeDecimal, afterDecimal = _a.afterDecimal, addNegation = _a.addNegation; // eslint-disable-line prefer-const
489
- //clear only if something got deleted
490
- if (numericString.length < lastNumStr.length && beforeDecimal === "" && !parseFloat(afterDecimal)) {
450
+ var numericString = removeFormatting(value);
451
+ var _a = splitDecimal(numericString), beforeDecimal = _a.beforeDecimal, afterDecimal = _a.afterDecimal, addNegation = _a.addNegation;
452
+ if (numericString.length < lastNumStr.length &&
453
+ beforeDecimal === "" &&
454
+ !parseFloat(afterDecimal)) {
491
455
  return addNegation ? "-" : "";
492
456
  }
493
457
  }
494
458
  return value;
495
- };
496
- CurrencyFormat.prototype.onChange = function (e) {
497
- e.persist();
459
+ }, [
460
+ state.numAsString,
461
+ format,
462
+ checkIfFormatGotDeleted,
463
+ removeFormatting,
464
+ splitDecimal,
465
+ ]);
466
+ // Event handlers
467
+ var handleChange = (0, react_1.useCallback)(function (e) {
498
468
  var el = e.target;
499
469
  var inputValue = el.value;
500
- var _a = this, state = _a.state, props = _a.props;
501
- var isAllowed = props.isAllowed;
502
470
  var lastValue = state.value || "";
503
- /*Max of selectionStart and selectionEnd is taken for the patch of pixel and other mobile device caret bug*/
504
- var currentCaretPosition = Math.max(el.selectionStart, el.selectionEnd);
505
- inputValue = this.correctInputValue(currentCaretPosition, lastValue, inputValue);
506
- var formattedValue = this.formatInput(inputValue) || "";
507
- var numAsString = this.removeFormatting(formattedValue);
471
+ var currentCaretPosition = Math.max(el.selectionStart || 0, el.selectionEnd || 0);
472
+ inputValue = correctInputValue(currentCaretPosition, lastValue, inputValue);
473
+ var formattedValue = formatInput(inputValue) || "";
474
+ var numAsString = removeFormatting(formattedValue);
508
475
  var valueObj = {
509
476
  formattedValue: formattedValue,
510
477
  value: numAsString,
511
478
  floatValue: parseFloat(numAsString),
479
+ name: name,
512
480
  };
513
- if (!isAllowed(valueObj)) {
481
+ if (isAllowed && !isAllowed(valueObj)) {
514
482
  formattedValue = lastValue;
515
483
  }
516
- //set the value imperatively, this is required for IE fix
517
484
  el.value = formattedValue;
518
- //get the caret position
519
- var caretPos = this.getCaretPosition(inputValue, formattedValue, currentCaretPosition);
520
- //set caret position
521
- this.setPatchedCaretPosition(el, caretPos, formattedValue);
522
- //change the state
485
+ var caretPos = getCaretPosition(inputValue, formattedValue, currentCaretPosition);
486
+ setPatchedCaretPosition(el, caretPos, formattedValue);
523
487
  if (formattedValue !== lastValue) {
524
- this.setState({ value: formattedValue, numAsString: numAsString }, function () {
525
- props.onValueChange(valueObj);
526
- props.onChange(e);
527
- });
488
+ setState({ value: formattedValue, numAsString: numAsString });
489
+ onValueChange === null || onValueChange === void 0 ? void 0 : onValueChange(valueObj, { event: e, source: "event" });
490
+ onChangeProp === null || onChangeProp === void 0 ? void 0 : onChangeProp(e);
528
491
  }
529
492
  else {
530
- props.onChange(e);
531
- }
532
- };
533
- CurrencyFormat.prototype.onBlur = function (e) {
534
- var _a = this, props = _a.props, state = _a.state;
535
- var format = props.format, onBlur = props.onBlur;
493
+ onChangeProp === null || onChangeProp === void 0 ? void 0 : onChangeProp(e);
494
+ }
495
+ }, [
496
+ state.value,
497
+ correctInputValue,
498
+ formatInput,
499
+ removeFormatting,
500
+ isAllowed,
501
+ getCaretPosition,
502
+ setPatchedCaretPosition,
503
+ onValueChange,
504
+ onChangeProp,
505
+ name,
506
+ ]);
507
+ var handleBlur = (0, react_1.useCallback)(function (e) {
536
508
  var numAsString = state.numAsString;
537
509
  var lastValue = state.value;
538
510
  if (!format) {
539
- numAsString = (0, utils_1.fixLeadingZero)(numAsString);
540
- var formattedValue = this.formatNumString(numAsString);
541
- var valueObj_1 = {
511
+ numAsString = (0, utils_1.fixLeadingZero)(numAsString) || "";
512
+ var formattedValue = formatNumString(numAsString);
513
+ var valueObj = {
542
514
  formattedValue: formattedValue,
543
515
  value: numAsString,
544
516
  floatValue: parseFloat(numAsString),
517
+ name: name,
545
518
  };
546
- //change the state
547
519
  if (formattedValue !== lastValue) {
548
- // the event needs to be persisted because its properties can be accessed in an asynchronous way
549
- e.persist();
550
- this.setState({ value: formattedValue, numAsString: numAsString }, function () {
551
- props.onValueChange(valueObj_1);
552
- onBlur(e);
553
- });
520
+ setState({ value: formattedValue, numAsString: numAsString });
521
+ onValueChange === null || onValueChange === void 0 ? void 0 : onValueChange(valueObj, { source: "event" });
522
+ onBlurProp === null || onBlurProp === void 0 ? void 0 : onBlurProp(e);
554
523
  return;
555
524
  }
556
525
  }
557
- onBlur(e);
558
- };
559
- CurrencyFormat.prototype.onKeyDown = function (e) {
526
+ onBlurProp === null || onBlurProp === void 0 ? void 0 : onBlurProp(e);
527
+ }, [state, format, formatNumString, onValueChange, onBlurProp, name]);
528
+ var handleKeyDown = (0, react_1.useCallback)(function (e) {
560
529
  var el = e.target;
561
530
  var key = e.key;
562
- var selectionEnd = el.selectionEnd, value = el.value;
563
- var selectionStart = el.selectionStart;
531
+ var selectionEnd = el.selectionEnd, value = el.value, selectionStart = el.selectionStart;
564
532
  var expectedCaretPosition;
565
- var _a = this.props, decimalScale = _a.decimalScale, fixedDecimalScale = _a.fixedDecimalScale, prefix = _a.prefix, suffix = _a.suffix, format = _a.format, onKeyDown = _a.onKeyDown;
566
533
  var ignoreDecimalSeparator = decimalScale !== undefined && fixedDecimalScale;
567
- var numRegex = this.getNumberRegex(false, ignoreDecimalSeparator);
534
+ var numRegex = getNumberRegex(false, ignoreDecimalSeparator);
568
535
  var negativeRegex = new RegExp("-");
569
536
  var isPatternFormat = typeof format === "string";
570
- //Handle backspace and delete against non numerical/decimal characters or arrow keys
571
537
  if (key === "ArrowLeft" || key === "Backspace") {
572
- expectedCaretPosition = selectionStart - 1;
538
+ expectedCaretPosition = (selectionStart || 0) - 1;
573
539
  }
574
540
  else if (key === "ArrowRight") {
575
- expectedCaretPosition = selectionStart + 1;
541
+ expectedCaretPosition = (selectionStart || 0) + 1;
576
542
  }
577
543
  else if (key === "Delete") {
578
- expectedCaretPosition = selectionStart;
544
+ expectedCaretPosition = selectionStart || 0;
579
545
  }
580
- //if expectedCaretPosition is not set it means we don't want to Handle keyDown
581
- //also if multiple characters are selected don't handle
582
- if (expectedCaretPosition === undefined || selectionStart !== selectionEnd) {
583
- onKeyDown(e);
546
+ if (expectedCaretPosition === undefined ||
547
+ selectionStart !== selectionEnd) {
548
+ onKeyDownProp === null || onKeyDownProp === void 0 ? void 0 : onKeyDownProp(e);
584
549
  return;
585
550
  }
586
551
  var newCaretPosition = expectedCaretPosition;
587
- var leftBound = isPatternFormat ? format.indexOf("#") : prefix.length;
588
- var rightBound = isPatternFormat ? format.lastIndexOf("#") + 1 : value.length - suffix.length;
552
+ var leftBound = isPatternFormat
553
+ ? format.indexOf("#")
554
+ : prefix.length;
555
+ var rightBound = isPatternFormat
556
+ ? format.lastIndexOf("#") + 1
557
+ : value.length - suffix.length;
589
558
  if (key === "ArrowLeft" || key === "ArrowRight") {
590
559
  var direction = key === "ArrowLeft" ? "left" : "right";
591
- newCaretPosition = this.correctCaretPosition(value, expectedCaretPosition, direction);
560
+ newCaretPosition = correctCaretPosition(value, expectedCaretPosition, direction);
592
561
  }
593
562
  else if (key === "Delete" &&
594
563
  !numRegex.test(value[expectedCaretPosition]) &&
595
564
  !negativeRegex.test(value[expectedCaretPosition])) {
596
- while (!numRegex.test(value[newCaretPosition]) && newCaretPosition < rightBound)
565
+ while (!numRegex.test(value[newCaretPosition]) &&
566
+ newCaretPosition < rightBound) {
597
567
  newCaretPosition++;
568
+ }
598
569
  }
599
570
  else if (key === "Backspace" &&
600
571
  !numRegex.test(value[expectedCaretPosition]) &&
601
572
  !negativeRegex.test(value[expectedCaretPosition])) {
602
- while (!numRegex.test(value[newCaretPosition - 1]) && newCaretPosition > leftBound) {
573
+ while (!numRegex.test(value[newCaretPosition - 1]) &&
574
+ newCaretPosition > leftBound) {
603
575
  newCaretPosition--;
604
576
  }
605
- newCaretPosition = this.correctCaretPosition(value, newCaretPosition, "left");
577
+ newCaretPosition = correctCaretPosition(value, newCaretPosition, "left");
606
578
  }
607
579
  if (newCaretPosition !== expectedCaretPosition ||
608
580
  expectedCaretPosition < leftBound ||
609
581
  expectedCaretPosition > rightBound) {
610
582
  e.preventDefault();
611
- this.setPatchedCaretPosition(el, newCaretPosition, value);
612
- }
613
- /* NOTE: this is just required for unit test as we need to get the newCaretPosition,
614
- Remove this when you find different solution */
615
- if (e.isUnitTestRun) {
616
- this.setPatchedCaretPosition(el, newCaretPosition, value);
617
- }
618
- this.props.onKeyDown(e);
619
- };
620
- /** required to handle the caret position when click anywhere within the input **/
621
- CurrencyFormat.prototype.onMouseUp = function (e) {
583
+ setPatchedCaretPosition(el, newCaretPosition, value);
584
+ }
585
+ // For unit tests
586
+ if (e
587
+ .isUnitTestRun) {
588
+ setPatchedCaretPosition(el, newCaretPosition, value);
589
+ }
590
+ onKeyDownProp === null || onKeyDownProp === void 0 ? void 0 : onKeyDownProp(e);
591
+ }, [
592
+ decimalScale,
593
+ fixedDecimalScale,
594
+ getNumberRegex,
595
+ format,
596
+ prefix,
597
+ suffix,
598
+ correctCaretPosition,
599
+ setPatchedCaretPosition,
600
+ onKeyDownProp,
601
+ ]);
602
+ var handleMouseUp = (0, react_1.useCallback)(function (e) {
622
603
  var el = e.target;
623
604
  var selectionStart = el.selectionStart, selectionEnd = el.selectionEnd, value = el.value;
624
605
  if (selectionStart === selectionEnd) {
625
- var caretPostion = this.correctCaretPosition(value, selectionStart);
626
- if (caretPostion !== selectionStart) {
627
- this.setPatchedCaretPosition(el, caretPostion, value);
606
+ var caretPosition = correctCaretPosition(value, selectionStart || 0);
607
+ if (caretPosition !== selectionStart) {
608
+ setPatchedCaretPosition(el, caretPosition, value);
628
609
  }
629
610
  }
630
- this.props.onMouseUp(e);
631
- };
632
- CurrencyFormat.prototype.onFocus = function (e) {
633
- var _this = this;
634
- // Workaround Chrome and Safari bug https://bugs.chromium.org/p/chromium/issues/detail?id=779328
635
- // (onFocus event target selectionStart is always 0 before setTimeout)
636
- e.persist();
611
+ onMouseUpProp === null || onMouseUpProp === void 0 ? void 0 : onMouseUpProp(e);
612
+ }, [correctCaretPosition, setPatchedCaretPosition, onMouseUpProp]);
613
+ var handleFocus = (0, react_1.useCallback)(function (e) {
614
+ var el = e.target;
637
615
  setTimeout(function () {
638
- var el = e.target;
639
616
  var selectionStart = el.selectionStart, value = el.value;
640
- var caretPosition = _this.correctCaretPosition(value, selectionStart);
617
+ var caretPosition = correctCaretPosition(value, selectionStart || 0);
641
618
  if (caretPosition !== selectionStart) {
642
- _this.setPatchedCaretPosition(el, caretPosition, value);
619
+ setPatchedCaretPosition(el, caretPosition, value);
643
620
  }
644
- _this.props.onFocus(e);
621
+ onFocusProp === null || onFocusProp === void 0 ? void 0 : onFocusProp(e);
645
622
  });
646
- };
647
- CurrencyFormat.prototype.render = function () {
648
- var _a = this.props, type = _a.type, displayType = _a.displayType, customInput = _a.customInput, renderText = _a.renderText, placeholder = _a.placeholder, className = _a.className;
649
- var value = this.state.value;
650
- var otherProps = (0, utils_1.omit)(this.props, propTypes);
651
- var inputProps = Object.assign({}, otherProps, {
652
- type: type,
653
- value: value.replace(/^\./, ""),
654
- onChange: this.onChange,
655
- onKeyDown: this.onKeyDown,
656
- onMouseUp: this.onMouseUp,
657
- onFocus: this.onFocus,
658
- onBlur: this.onBlur,
659
- placeholder: placeholder,
660
- className: className
661
- });
662
- if (displayType === "text") {
663
- return renderText ? value || null : react_1.default.createElement("span", tslib_1.__assign({}, otherProps), value);
664
- }
665
- else if (customInput) {
666
- var CustomInput = customInput;
667
- return react_1.default.createElement(CustomInput, tslib_1.__assign({}, inputProps));
668
- }
669
- return react_1.default.createElement("input", tslib_1.__assign({}, inputProps));
670
- };
671
- CurrencyFormat.defaultProps = {
672
- displayType: "input",
673
- decimalSeparator: ".",
674
- thousandSpacing: "3",
675
- thousandSeparator: ",",
676
- fixedDecimalScale: false,
677
- prefix: "",
678
- suffix: "",
679
- allowNegative: true,
680
- isNumericString: false,
681
- type: "text",
682
- onValueChange: utils_1.noop,
683
- onChange: utils_1.noop,
684
- onKeyDown: utils_1.noop,
685
- onMouseUp: utils_1.noop,
686
- onFocus: utils_1.noop,
687
- onBlur: utils_1.noop,
688
- isAllowed: utils_1.returnTrue,
689
- className: "",
690
- placeholder: ""
691
- };
692
- return CurrencyFormat;
693
- }(react_1.Component));
623
+ }, [correctCaretPosition, setPatchedCaretPosition, onFocusProp]);
624
+ // Effect to validate props on mount and update
625
+ (0, react_1.useEffect)(function () {
626
+ validateProps();
627
+ }, [validateProps]);
628
+ // Effect to update value when props change
629
+ (0, react_1.useEffect)(function () {
630
+ var prevProps = prevPropsRef.current;
631
+ if (prevProps !== props) {
632
+ var lastNumStr = state.numAsString || "";
633
+ var formattedValue = valueProp === undefined
634
+ ? formatNumString(lastNumStr)
635
+ : formatValueProp();
636
+ if (formattedValue !== state.value) {
637
+ var newNumAsString = removeFormatting(formattedValue);
638
+ setState({
639
+ value: formattedValue,
640
+ numAsString: newNumAsString,
641
+ });
642
+ // Notify about prop-driven value change
643
+ if (onValueChange) {
644
+ var valueObj = {
645
+ formattedValue: formattedValue,
646
+ value: newNumAsString,
647
+ floatValue: parseFloat(newNumAsString),
648
+ name: name,
649
+ };
650
+ onValueChange(valueObj, { source: "prop" });
651
+ }
652
+ }
653
+ }
654
+ prevPropsRef.current = props;
655
+ }, [
656
+ props,
657
+ valueProp,
658
+ state,
659
+ formatNumString,
660
+ formatValueProp,
661
+ removeFormatting,
662
+ onValueChange,
663
+ name,
664
+ ]);
665
+ // Effect to call getInputRef callback
666
+ (0, react_1.useEffect)(function () {
667
+ if (getInputRef) {
668
+ getInputRef(inputRef.current);
669
+ }
670
+ }, [getInputRef]);
671
+ // Get other props to pass to input
672
+ var otherProps = (0, react_1.useMemo)(function () { return (0, utils_1.omit)(restProps, PROPS_TO_OMIT); }, [restProps]);
673
+ // Build input props
674
+ var inputProps = (0, react_1.useMemo)(function () { return (tslib_1.__assign(tslib_1.__assign({}, otherProps), { type: type, name: name, value: (state.value || "").replace(/^\./, ""), onChange: handleChange, onKeyDown: handleKeyDown, onMouseUp: handleMouseUp, onFocus: handleFocus, onBlur: handleBlur, placeholder: placeholder, className: className, ref: inputRef })); }, [
675
+ otherProps,
676
+ type,
677
+ name,
678
+ state.value,
679
+ handleChange,
680
+ handleKeyDown,
681
+ handleMouseUp,
682
+ handleFocus,
683
+ handleBlur,
684
+ placeholder,
685
+ className,
686
+ ]);
687
+ // Render
688
+ if (displayType === "text") {
689
+ return renderText ? (react_1.default.createElement(react_1.default.Fragment, null, renderText(state.value || "", otherProps))) : (react_1.default.createElement("span", tslib_1.__assign({}, otherProps), state.value));
690
+ }
691
+ if (customInput) {
692
+ var CustomInput = customInput;
693
+ return react_1.default.createElement(CustomInput, tslib_1.__assign({}, inputProps));
694
+ }
695
+ return react_1.default.createElement("input", tslib_1.__assign({}, inputProps));
696
+ });
697
+ CurrencyFormat.displayName = "CurrencyFormat";
694
698
  exports.default = CurrencyFormat;
695
699
  //# sourceMappingURL=index.js.map