@alfalab/core-components-number-input 1.0.2 → 1.0.4

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.
package/Component.d.ts CHANGED
@@ -1,126 +1,6 @@
1
1
  /// <reference types="react" />
2
2
  import React from 'react';
3
- import { ChangeEvent, InputHTMLAttributes, MouseEvent, ReactNode } from "react";
4
- type InputProps = Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type" | "value" | "defaultValue" | "onChange" | "onClick" | "onMouseDown" | "enterKeyHint"> & {
5
- /**
6
- * Значение поля ввода
7
- */
8
- value?: string;
9
- /**
10
- * Начальное значение поля
11
- */
12
- defaultValue?: string;
13
- /**
14
- * Растягивает компонент на ширину контейнера
15
- */
16
- block?: boolean;
17
- /**
18
- * Крестик для очистки поля
19
- */
20
- clear?: boolean;
21
- /**
22
- * Размер компонента
23
- */
24
- size?: "s" | "m" | "l" | "xl";
25
- /**
26
- * Набор цветов для компонента
27
- */
28
- colors?: "default" | "inverted";
29
- /**
30
- * Отображение ошибки
31
- */
32
- error?: ReactNode | boolean;
33
- /**
34
- * Отображение иконки успеха
35
- */
36
- success?: boolean;
37
- /**
38
- * Текст подсказки
39
- */
40
- hint?: ReactNode;
41
- /**
42
- * Лейбл компонента
43
- */
44
- label?: React.ReactNode;
45
- /**
46
- * Вид лейбла внутри / снаружи
47
- */
48
- labelView?: "inner" | "outer";
49
- /**
50
- * Атрибут type
51
- */
52
- type?: "number" | "card" | "email" | "money" | "password" | "tel" | "text";
53
- /**
54
- * Ref для обертки input
55
- */
56
- wrapperRef?: React.Ref<HTMLDivElement>;
57
- /**
58
- * Слот слева
59
- */
60
- leftAddons?: React.ReactNode;
61
- /**
62
- * Слот справа
63
- */
64
- rightAddons?: React.ReactNode;
65
- /**
66
- * Слот под инпутом
67
- */
68
- bottomAddons?: React.ReactNode;
69
- /**
70
- * Дополнительный класс
71
- */
72
- className?: string;
73
- /**
74
- * Дополнительный класс для поля
75
- */
76
- fieldClassName?: string;
77
- /**
78
- * Дополнительный класс инпута
79
- */
80
- inputClassName?: string;
81
- /**
82
- * Дополнительный класс для лейбла
83
- */
84
- labelClassName?: string;
85
- /**
86
- * Дополнительный класс для аддонов
87
- */
88
- addonsClassName?: string;
89
- /**
90
- * Класс, который будет установлен при фокусе
91
- */
92
- focusedClassName?: string;
93
- /**
94
- * Класс, который будет установлен, если в поле есть значение
95
- */
96
- filledClassName?: string;
97
- /**
98
- * Обработчик поля ввода
99
- */
100
- onChange?: (event: ChangeEvent<HTMLInputElement>, payload: {
101
- value: string;
102
- }) => void;
103
- /**
104
- * Обработчик нажатия на кнопку очистки
105
- */
106
- onClear?: (event: MouseEvent<HTMLButtonElement>) => void;
107
- /**
108
- * Обработчик клика по полю
109
- */
110
- onClick?: (event: MouseEvent<HTMLDivElement>) => void;
111
- /**
112
- * Обработчик MouseDown по полю
113
- */
114
- onMouseDown?: (event: MouseEvent<HTMLDivElement>) => void;
115
- /**
116
- * Обработчик MouseUp по полю
117
- */
118
- onMouseUp?: (event: MouseEvent<HTMLDivElement>) => void;
119
- /**
120
- * Идентификатор для систем автоматизированного тестирования
121
- */
122
- dataTestId?: string;
123
- };
3
+ import { InputProps } from "@alfalab/core-components-input";
124
4
  type NumberInputProps = Omit<InputProps, 'value' | 'onChange' | 'type'> & {
125
5
  /**
126
6
  * Значение поля ввода
@@ -164,7 +44,7 @@ declare const NumberInput: React.ForwardRefExoticComponent<Omit<InputProps, "typ
164
44
  /**
165
45
  * Разделитель ',' или '.'
166
46
  */
167
- separator?: "." | "," | undefined;
47
+ separator?: "," | "." | undefined;
168
48
  /**
169
49
  * Количество символов после разделителя
170
50
  */
package/Component.js CHANGED
@@ -1,55 +1,18 @@
1
1
  'use strict';
2
2
 
3
+ var tslib = require('tslib');
3
4
  var React = require('react');
4
5
  var mergeRefs = require('react-merge-refs');
5
- var coreComponentsMaskedInput = require('@alfalab/core-components-masked-input');
6
+ var coreComponentsInput = require('@alfalab/core-components-input');
7
+ var utils = require('./utils.js');
6
8
 
7
9
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
8
10
 
9
11
  var React__default = /*#__PURE__*/_interopDefaultCompat(React);
10
12
  var mergeRefs__default = /*#__PURE__*/_interopDefaultCompat(mergeRefs);
11
13
 
12
- /******************************************************************************
13
- Copyright (c) Microsoft Corporation.
14
-
15
- Permission to use, copy, modify, and/or distribute this software for any
16
- purpose with or without fee is hereby granted.
17
-
18
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
19
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
20
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
21
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
22
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
23
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
24
- PERFORMANCE OF THIS SOFTWARE.
25
- ***************************************************************************** */
26
- var __assign = function () {
27
- __assign = Object.assign || function __assign(t) {
28
- for (var s, i = 1, n = arguments.length; i < n; i++) {
29
- s = arguments[i];
30
- for (var p in s)
31
- if (Object.prototype.hasOwnProperty.call(s, p))
32
- t[p] = s[p];
33
- }
34
- return t;
35
- };
36
- return __assign.apply(this, arguments);
37
- };
38
- function __rest(s, e) {
39
- var t = {};
40
- for (var p in s)
41
- if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
42
- t[p] = s[p];
43
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
44
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
45
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
46
- t[p[i]] = s[p[i]];
47
- }
48
- return t;
49
- }
50
-
51
14
  var NumberInput = React__default.default.forwardRef(function (_a, ref) {
52
- var propValue = _a.value, onChange = _a.onChange, onBlur = _a.onBlur, _b = _a.allowSigns, allowSigns = _b === void 0 ? true : _b, _c = _a.separator, separator = _c === void 0 ? ',' : _c, fractionLength = _a.fractionLength, defaultValue = _a.defaultValue, restProps = __rest(_a, ["value", "onChange", "onBlur", "allowSigns", "separator", "fractionLength", "defaultValue"]);
15
+ var propValue = _a.value, onChange = _a.onChange, onBlur = _a.onBlur, _b = _a.allowSigns, allowSigns = _b === void 0 ? true : _b, _c = _a.separator, separator = _c === void 0 ? ',' : _c, fractionLength = _a.fractionLength, defaultValue = _a.defaultValue, restProps = tslib.__rest(_a, ["value", "onChange", "onBlur", "allowSigns", "separator", "fractionLength", "defaultValue"]);
53
16
  var uncontrolled = propValue === undefined;
54
17
  var inputRef = React.useRef(null);
55
18
  var _d = React.useState(defaultValue || ''), value = _d[0], setValue = _d[1];
@@ -59,72 +22,59 @@ var NumberInput = React__default.default.forwardRef(function (_a, ref) {
59
22
  }
60
23
  return parseFloat(valueString);
61
24
  };
62
- var handleChange = function (event, payload) {
63
- var input = event.target;
64
- var positionСursor = input.selectionStart || 0;
65
- if (input.value[positionСursor] === separator) {
66
- var index = input.selectionStart + 1;
67
- input.selectionStart = index;
68
- }
69
- if (onChange) {
70
- onChange(event, {
71
- value: getNumberValueFromStr(input.value),
72
- valueString: input.value,
73
- });
74
- }
75
- if (uncontrolled) {
76
- setValue(payload.value);
25
+ var getNumberRegExp = function () {
26
+ var reStr = '[0-9]+';
27
+ if (fractionLength !== 0) {
28
+ reStr = "".concat(reStr, "[").concat(utils.SEPARATORS.map(function (s) { return "\\".concat(s); }).join(''), "]?[0-9]{0,").concat(fractionLength || Number.MAX_SAFE_INTEGER, "}");
77
29
  }
30
+ return new RegExp("^".concat(reStr, "$"));
78
31
  };
79
- var formatSeparatorValue = function (separator, rawValue) {
80
- var singsRegexp = /\W+/;
81
- var sings = singsRegexp.exec(rawValue);
82
- if (sings && sings[0] !== ',' && sings[0] !== '.') {
83
- return rawValue.replace(sings[0], '');
84
- }
85
- var separatorRegexp = /\.|,/;
86
- if (rawValue.length === 1 && separatorRegexp.test(rawValue))
87
- return '';
88
- if (separator === ',') {
89
- return rawValue.replace('.', ',');
90
- }
91
- if (separator === '.') {
92
- return rawValue.replace(',', '.');
32
+ var restoreCaret = function (target) {
33
+ var input = target;
34
+ var positionCursor = input.selectionStart || 0;
35
+ var isEndPosition = input.value.length === positionCursor;
36
+ var enteredSign = utils.SIGNS.some(function (s) { return s === input.value[positionCursor - 1]; });
37
+ var enteredSeparator = utils.SEPARATORS.filter(function (s) { return s !== separator; }).some(function (s) { return s === input.value[positionCursor - 1]; });
38
+ var shouldRestore = enteredSeparator || enteredSign;
39
+ if (!isEndPosition && shouldRestore) {
40
+ setTimeout(function () {
41
+ input.selectionStart = positionCursor;
42
+ input.selectionEnd = positionCursor;
43
+ });
93
44
  }
94
- return rawValue;
95
45
  };
96
- var handleBeforeDisplay = function (conformedValue, _a) {
97
- var rawValue = _a.rawValue, previousConformedValue = _a.previousConformedValue;
98
- var isTwoSign = rawValue.length - conformedValue.length >= 1;
99
- var isOneSign = rawValue.length - conformedValue.length === 1;
100
- var signRegexp = /\.|,/;
101
- if (fractionLength === 0 && signRegexp.test(rawValue)) {
102
- return previousConformedValue;
103
- }
104
- var zeroRegexp = /^[+|-]?00+$/;
105
- if (zeroRegexp.test(rawValue)) {
106
- var index = rawValue.search(/[+|-]/) !== -1 ? 2 : 1;
107
- return rawValue.slice(0, index);
108
- }
109
- if (isTwoSign && previousConformedValue) {
110
- if (rawValue.length !== conformedValue.length && fractionLength) {
111
- var valueLength = conformedValue.length - fractionLength;
112
- var sign = separator === ',' ? '.' : ',';
113
- if (rawValue.indexOf(sign) !== valueLength &&
114
- rawValue.indexOf(sign) !== conformedValue.length) {
115
- return previousConformedValue;
116
- }
46
+ var handleChange = function (event) {
47
+ var input = event.target;
48
+ var numberRe = getNumberRegExp();
49
+ var testedValue = allowSigns && utils.SIGNS.some(function (s) { return s === input.value[0]; })
50
+ ? input.value.slice(1)
51
+ : input.value;
52
+ if (testedValue === '' || numberRe.test(testedValue)) {
53
+ var newValue = input.value.replace(utils.createSeparatorsRegExp(), separator);
54
+ if (onChange) {
55
+ onChange(event, {
56
+ value: getNumberValueFromStr(newValue),
57
+ valueString: newValue,
58
+ });
117
59
  }
118
- var hasSign = conformedValue.includes(separator);
119
- if (!hasSign && isOneSign) {
120
- return formatSeparatorValue(separator, rawValue);
60
+ if (uncontrolled) {
61
+ setValue(newValue);
121
62
  }
122
- return previousConformedValue;
63
+ restoreCaret(input);
123
64
  }
124
- if (isOneSign && !uncontrolled) {
125
- return formatSeparatorValue(separator, rawValue);
65
+ };
66
+ var handleKeyDown = function (event) {
67
+ var disallowedSymbols = /[/|?!@#$%^&*()_=A-Za-zА-Яа-яЁё ]/;
68
+ var oneKeyPress = !event.altKey && !event.metaKey && !event.ctrlKey && !event.shiftKey;
69
+ // Запрещаем вводить неразрешенные символы за исключением комбинций клавиш
70
+ if (oneKeyPress && event.key.length === 1 && disallowedSymbols.test(event.key)) {
71
+ event.preventDefault();
72
+ }
73
+ // Запрещаем вводить второй сепаратор
74
+ if (utils.SEPARATORS.some(function (s) { return s === event.key; }) &&
75
+ (event.target.value.match(utils.createSeparatorsRegExp()) || []).length) {
76
+ event.preventDefault();
126
77
  }
127
- return conformedValue;
128
78
  };
129
79
  var handleBlur = function (event) {
130
80
  var valueBlur = event.target.value.replace(new RegExp("\\".concat(separator, "$")), '');
@@ -140,25 +90,8 @@ var NumberInput = React__default.default.forwardRef(function (_a, ref) {
140
90
  if (onBlur)
141
91
  onBlur(event);
142
92
  };
143
- var handleMask = function (valueInput) {
144
- var mask = allowSigns ? [/[+-\d]/] : [/\d/];
145
- if (valueInput.length <= 1)
146
- return mask;
147
- mask.push.apply(mask, Array(valueInput.length - 1).fill(/\d/));
148
- var dotIndex = valueInput.indexOf(separator);
149
- var signRegexp = new RegExp("[\\d".concat(separator, "]"));
150
- var startWithDigit = signRegexp.test(valueInput[0]);
151
- if (dotIndex > (startWithDigit ? 0 : 1)) {
152
- mask[dotIndex] = signRegexp;
153
- }
154
- if (fractionLength && dotIndex !== -1) {
155
- var endMaskLength = dotIndex + fractionLength + 1;
156
- mask = mask.slice(0, endMaskLength);
157
- }
158
- return mask;
159
- };
160
93
  var visibleValue = uncontrolled ? value : propValue === null || propValue === void 0 ? void 0 : propValue.toString();
161
- return (React__default.default.createElement(coreComponentsMaskedInput.MaskedInput, __assign({ ref: mergeRefs__default.default([ref, inputRef]), mask: handleMask, value: visibleValue, onBlur: handleBlur, onChange: handleChange, inputMode: 'decimal', onBeforeDisplay: handleBeforeDisplay }, restProps)));
94
+ return (React__default.default.createElement(coreComponentsInput.Input, tslib.__assign({ ref: mergeRefs__default.default([ref, inputRef]), value: visibleValue, onBlur: handleBlur, onChange: handleChange, onKeyDown: handleKeyDown, inputMode: 'decimal' }, restProps)));
162
95
  });
163
96
 
164
97
  exports.NumberInput = NumberInput;
@@ -1,126 +1,6 @@
1
1
  /// <reference types="react" />
2
2
  import React from 'react';
3
- import { ChangeEvent, InputHTMLAttributes, MouseEvent, ReactNode } from "react";
4
- type InputProps = Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type" | "value" | "defaultValue" | "onChange" | "onClick" | "onMouseDown" | "enterKeyHint"> & {
5
- /**
6
- * Значение поля ввода
7
- */
8
- value?: string;
9
- /**
10
- * Начальное значение поля
11
- */
12
- defaultValue?: string;
13
- /**
14
- * Растягивает компонент на ширину контейнера
15
- */
16
- block?: boolean;
17
- /**
18
- * Крестик для очистки поля
19
- */
20
- clear?: boolean;
21
- /**
22
- * Размер компонента
23
- */
24
- size?: "s" | "m" | "l" | "xl";
25
- /**
26
- * Набор цветов для компонента
27
- */
28
- colors?: "default" | "inverted";
29
- /**
30
- * Отображение ошибки
31
- */
32
- error?: ReactNode | boolean;
33
- /**
34
- * Отображение иконки успеха
35
- */
36
- success?: boolean;
37
- /**
38
- * Текст подсказки
39
- */
40
- hint?: ReactNode;
41
- /**
42
- * Лейбл компонента
43
- */
44
- label?: React.ReactNode;
45
- /**
46
- * Вид лейбла внутри / снаружи
47
- */
48
- labelView?: "inner" | "outer";
49
- /**
50
- * Атрибут type
51
- */
52
- type?: "number" | "card" | "email" | "money" | "password" | "tel" | "text";
53
- /**
54
- * Ref для обертки input
55
- */
56
- wrapperRef?: React.Ref<HTMLDivElement>;
57
- /**
58
- * Слот слева
59
- */
60
- leftAddons?: React.ReactNode;
61
- /**
62
- * Слот справа
63
- */
64
- rightAddons?: React.ReactNode;
65
- /**
66
- * Слот под инпутом
67
- */
68
- bottomAddons?: React.ReactNode;
69
- /**
70
- * Дополнительный класс
71
- */
72
- className?: string;
73
- /**
74
- * Дополнительный класс для поля
75
- */
76
- fieldClassName?: string;
77
- /**
78
- * Дополнительный класс инпута
79
- */
80
- inputClassName?: string;
81
- /**
82
- * Дополнительный класс для лейбла
83
- */
84
- labelClassName?: string;
85
- /**
86
- * Дополнительный класс для аддонов
87
- */
88
- addonsClassName?: string;
89
- /**
90
- * Класс, который будет установлен при фокусе
91
- */
92
- focusedClassName?: string;
93
- /**
94
- * Класс, который будет установлен, если в поле есть значение
95
- */
96
- filledClassName?: string;
97
- /**
98
- * Обработчик поля ввода
99
- */
100
- onChange?: (event: ChangeEvent<HTMLInputElement>, payload: {
101
- value: string;
102
- }) => void;
103
- /**
104
- * Обработчик нажатия на кнопку очистки
105
- */
106
- onClear?: (event: MouseEvent<HTMLButtonElement>) => void;
107
- /**
108
- * Обработчик клика по полю
109
- */
110
- onClick?: (event: MouseEvent<HTMLDivElement>) => void;
111
- /**
112
- * Обработчик MouseDown по полю
113
- */
114
- onMouseDown?: (event: MouseEvent<HTMLDivElement>) => void;
115
- /**
116
- * Обработчик MouseUp по полю
117
- */
118
- onMouseUp?: (event: MouseEvent<HTMLDivElement>) => void;
119
- /**
120
- * Идентификатор для систем автоматизированного тестирования
121
- */
122
- dataTestId?: string;
123
- };
3
+ import { InputProps } from "@alfalab/core-components-input";
124
4
  type NumberInputProps = Omit<InputProps, 'value' | 'onChange' | 'type'> & {
125
5
  /**
126
6
  * Значение поля ввода
@@ -164,7 +44,7 @@ declare const NumberInput: React.ForwardRefExoticComponent<Omit<InputProps, "typ
164
44
  /**
165
45
  * Разделитель ',' или '.'
166
46
  */
167
- separator?: "." | "," | undefined;
47
+ separator?: "," | "." | undefined;
168
48
  /**
169
49
  * Количество символов после разделителя
170
50
  */