intelicoreact 0.0.7 → 0.0.8
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/dist/Atomic/FormElements/Dropdown/Dropdown.js +20 -19
- package/dist/Atomic/FormElements/Input/Input.js +85 -46
- package/dist/Atomic/FormElements/Input/Input.stories.js +16 -22
- package/dist/Atomic/FormElements/InputDateRange/InputDateRange.js +18 -43
- package/dist/Atomic/FormElements/InputDateRange/InputDateRange.scss +42 -10
- package/dist/Atomic/FormElements/InputDateRange/InputDateRange.stories.js +3 -156
- package/dist/Atomic/FormElements/InputDateRange/components/Datepicker.js +11 -9
- package/dist/Atomic/FormElements/InputDateRange/components/SelectItem.js +3 -3
- package/dist/Atomic/FormElements/NumericInput/NumericInput.js +254 -0
- package/dist/Atomic/FormElements/NumericInput/NumericInput.scss +135 -0
- package/dist/Atomic/FormElements/NumericInput/NumericInput.stories.js +121 -0
- package/dist/Atomic/UI/Arrow/Arrow.js +6 -6
- package/dist/Constants/index.constants.js +8 -0
- package/dist/Functions/inputExecutor.js +58 -0
- package/package.json +6 -5
- package/src/Atomic/FormElements/Dropdown/Dropdown.js +36 -39
- package/src/Atomic/FormElements/Input/Input.js +86 -36
- package/src/Atomic/FormElements/Input/Input.stories.js +40 -29
- package/src/Atomic/FormElements/InputDateRange/InputDateRange.js +187 -214
- package/src/Atomic/FormElements/InputDateRange/InputDateRange.scss +42 -10
- package/src/Atomic/FormElements/InputDateRange/InputDateRange.stories.js +35 -123
- package/src/Atomic/FormElements/InputDateRange/components/Datepicker.js +10 -7
- package/src/Atomic/FormElements/InputDateRange/components/OpenedPart.js +2 -2
- package/src/Atomic/FormElements/InputDateRange/components/SelectItem.js +1 -1
- package/src/Atomic/FormElements/NumericInput/NumericInput.js +220 -0
- package/src/Atomic/FormElements/NumericInput/NumericInput.scss +135 -0
- package/src/Atomic/FormElements/NumericInput/NumericInput.stories.js +94 -0
- package/src/Atomic/UI/Arrow/Arrow.js +4 -4
- package/src/Constants/index.constants.js +41 -0
- package/src/Functions/inputExecutor.js +62 -0
- package/src/Functions/utils.js +4 -1
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
|
|
5
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
6
|
+
|
|
7
|
+
Object.defineProperty(exports, "__esModule", {
|
|
8
|
+
value: true
|
|
9
|
+
});
|
|
10
|
+
exports.NumericInputTemplate = exports.default = void 0;
|
|
11
|
+
|
|
12
|
+
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
13
|
+
|
|
14
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
15
|
+
|
|
16
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
17
|
+
|
|
18
|
+
var _reactFeather = require("react-feather");
|
|
19
|
+
|
|
20
|
+
var _NumericInput = _interopRequireDefault(require("./NumericInput"));
|
|
21
|
+
|
|
22
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
23
|
+
|
|
24
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
25
|
+
|
|
26
|
+
global.lng = 'en';
|
|
27
|
+
var _default = {
|
|
28
|
+
title: 'Form Elements/NumericInput',
|
|
29
|
+
component: _NumericInput.default,
|
|
30
|
+
argTypes: {
|
|
31
|
+
disabled: {
|
|
32
|
+
description: 'boolean'
|
|
33
|
+
},
|
|
34
|
+
isInitialFocus: {
|
|
35
|
+
description: 'boolean - if true, the input will be focused on mount'
|
|
36
|
+
},
|
|
37
|
+
error: {
|
|
38
|
+
description: 'text - coloring input if is errored'
|
|
39
|
+
},
|
|
40
|
+
isPriceInput: {
|
|
41
|
+
description: 'boolean - if true, the input will be styled as PriceInput'
|
|
42
|
+
},
|
|
43
|
+
withDelete: {
|
|
44
|
+
description: 'boolean - add clear-cross by hover'
|
|
45
|
+
},
|
|
46
|
+
numStep: {
|
|
47
|
+
description: 'number/text - plus/minus buttons factor (default: 1)'
|
|
48
|
+
},
|
|
49
|
+
min: {
|
|
50
|
+
description: 'number/text - minimal number for numeric input'
|
|
51
|
+
},
|
|
52
|
+
max: {
|
|
53
|
+
description: 'number/text - maximal number for numeric input'
|
|
54
|
+
},
|
|
55
|
+
placeholder: {
|
|
56
|
+
description: 'text'
|
|
57
|
+
},
|
|
58
|
+
type: {
|
|
59
|
+
description: "'text', 'number', 'password', 'color', 'date', 'datetime-local', 'month', 'time', 'email', 'range'",
|
|
60
|
+
control: {
|
|
61
|
+
type: 'select',
|
|
62
|
+
options: ['text', 'number', 'password', 'color', 'date', 'datetime-local', 'month', 'time', 'email', 'range']
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
icon: {
|
|
66
|
+
description: 'JSX'
|
|
67
|
+
},
|
|
68
|
+
value: {
|
|
69
|
+
description: '(* - required prop)'
|
|
70
|
+
},
|
|
71
|
+
className: {
|
|
72
|
+
description: 'string'
|
|
73
|
+
},
|
|
74
|
+
mask: {
|
|
75
|
+
description: 'string: force input to masked https://www.npmjs.com/package/react-input-mask'
|
|
76
|
+
},
|
|
77
|
+
symbolsLimit: {
|
|
78
|
+
description: 'Set limit of symbols in input, overhead will be ignored'
|
|
79
|
+
},
|
|
80
|
+
onBlur: {
|
|
81
|
+
description: 'custom callback on blur'
|
|
82
|
+
},
|
|
83
|
+
onFocus: {
|
|
84
|
+
description: 'custom callback on focus'
|
|
85
|
+
},
|
|
86
|
+
onKeyUp: {
|
|
87
|
+
description: 'custom callback on keyup, returns event keyCode'
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
exports.default = _default;
|
|
92
|
+
|
|
93
|
+
var Template = function Template(args) {
|
|
94
|
+
var _useState = (0, _react.useState)(''),
|
|
95
|
+
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
|
|
96
|
+
value = _useState2[0],
|
|
97
|
+
setValue = _useState2[1];
|
|
98
|
+
|
|
99
|
+
return /*#__PURE__*/_react.default.createElement(_NumericInput.default, (0, _extends2.default)({}, args, {
|
|
100
|
+
value: value,
|
|
101
|
+
onChange: setValue
|
|
102
|
+
}));
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
var NumericInputTemplate = Template.bind({});
|
|
106
|
+
exports.NumericInputTemplate = NumericInputTemplate;
|
|
107
|
+
NumericInputTemplate.args = {
|
|
108
|
+
type: 'text',
|
|
109
|
+
disabled: false,
|
|
110
|
+
error: '',
|
|
111
|
+
isPriceInput: false,
|
|
112
|
+
mask: '',
|
|
113
|
+
withDelete: true,
|
|
114
|
+
isNumeric: false,
|
|
115
|
+
numStep: 100,
|
|
116
|
+
min: '0',
|
|
117
|
+
max: '15000',
|
|
118
|
+
symbolsLimit: 2,
|
|
119
|
+
placeholder: 'Placeholder',
|
|
120
|
+
icon: /*#__PURE__*/_react.default.createElement(_reactFeather.User, null)
|
|
121
|
+
};
|
|
@@ -58,9 +58,9 @@ var Arrow = function Arrow(_ref) {
|
|
|
58
58
|
}, /*#__PURE__*/_react.default.createElement("path", {
|
|
59
59
|
d: "M15 18L9 12L15 6",
|
|
60
60
|
stroke: color,
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
strokeWidth: "2",
|
|
62
|
+
strokeLinecap: "round",
|
|
63
|
+
strokeLinejoin: "round"
|
|
64
64
|
})) : /*#__PURE__*/_react.default.createElement("svg", {
|
|
65
65
|
width: "24",
|
|
66
66
|
height: "24",
|
|
@@ -70,9 +70,9 @@ var Arrow = function Arrow(_ref) {
|
|
|
70
70
|
}, /*#__PURE__*/_react.default.createElement("path", {
|
|
71
71
|
d: "M9 18L15 12L9 6",
|
|
72
72
|
stroke: color,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
strokeWidth: "2",
|
|
74
|
+
strokeLinecap: "round",
|
|
75
|
+
strokeLinejoin: "round"
|
|
76
76
|
})));
|
|
77
77
|
};
|
|
78
78
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.KEYBOARD_SERVICE_KEYS = void 0;
|
|
7
|
+
var KEYBOARD_SERVICE_KEYS = ['Escape', 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12', 'Tab', 'CapsLock', 'Shift', 'Control', 'Meta', 'Option', 'Alt', 'ContextMenu', 'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'NumLock', 'Backspace', 'Delete', 'Enter', 'Return', 'Insert', 'Home', 'End', 'PageUp', 'PageDown', 'PrintScreen', 'ScrollLock', 'Pause'];
|
|
8
|
+
exports.KEYBOARD_SERVICE_KEYS = KEYBOARD_SERVICE_KEYS;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.formatInput = void 0;
|
|
9
|
+
|
|
10
|
+
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
11
|
+
|
|
12
|
+
var formatInput = {
|
|
13
|
+
priceInput: {
|
|
14
|
+
addCommas: function addCommas(value) {
|
|
15
|
+
value = value.toString();
|
|
16
|
+
var isFraction = value.includes('.');
|
|
17
|
+
var valueBeforeDot = isFraction ? value.slice(0, value.indexOf('.')) : value;
|
|
18
|
+
var intPart = valueBeforeDot.split('').reverse().reduce(function (acc, item, idx) {
|
|
19
|
+
return idx % 3 === 0 && idx !== 0 ? [].concat((0, _toConsumableArray2.default)(acc), [',', item]) : [].concat((0, _toConsumableArray2.default)(acc), [item]);
|
|
20
|
+
}, []).reverse().join('');
|
|
21
|
+
return isFraction ? intPart + value.slice(value.indexOf('.')) : intPart;
|
|
22
|
+
},
|
|
23
|
+
removeComma: function removeComma(value) {
|
|
24
|
+
return parseFloat(value.toString().replace(/\,/g, ''));
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
onlyNumbers: function onlyNumbers(value) {
|
|
28
|
+
var isDot = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
29
|
+
var val = value.slice(0, 1) !== '0' && value.slice(0, 1) !== '.' ? value : value.slice(1);
|
|
30
|
+
if (isDot) return twoDigitAfterDot(val.replace(/[^0-9.]/g, ''));else return +val.toString().replace(/\D/g, '');
|
|
31
|
+
},
|
|
32
|
+
onlyString: function onlyString(value) {
|
|
33
|
+
return value.toString().replace(/[^a-z]/gi, '');
|
|
34
|
+
}
|
|
35
|
+
}; //обрезает числа после точки до 2х
|
|
36
|
+
// 342.23423432 -> 342.23
|
|
37
|
+
|
|
38
|
+
exports.formatInput = formatInput;
|
|
39
|
+
|
|
40
|
+
var twoDigitAfterDot = function twoDigitAfterDot(value) {
|
|
41
|
+
if (value.includes('.')) {
|
|
42
|
+
var valueAfterDot = value.slice(0, value.indexOf('.') + 3);
|
|
43
|
+
var rest = value.slice(value.indexOf('.') + 1, value.indexOf('.') + 3);
|
|
44
|
+
return allButTheFirstDotCutter(valueAfterDot);
|
|
45
|
+
} else {
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
}; //обрезает все точки кроме первой.
|
|
49
|
+
//для фомата "2 цифры после точки"
|
|
50
|
+
// нельзя = 123...
|
|
51
|
+
// можно 123.99
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
function allButTheFirstDotCutter(str) {
|
|
55
|
+
return str.replace(/^([^.]*\.)(.*)$/, function (a, b, c) {
|
|
56
|
+
return b + c.replace(/\./g, '');
|
|
57
|
+
});
|
|
58
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "intelicoreact",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.0.8",
|
|
4
|
+
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
@@ -14,14 +14,15 @@
|
|
|
14
14
|
"moment-timezone": "^0.5.34",
|
|
15
15
|
"react": "^17.0.2",
|
|
16
16
|
"react-feather": "^2.0.9",
|
|
17
|
-
"react-input-mask": "^2.0.4"
|
|
17
|
+
"react-input-mask": "^2.0.4",
|
|
18
|
+
"classnames": "^2.3.1"
|
|
18
19
|
},
|
|
19
20
|
"devDependencies": {
|
|
20
21
|
"@babel/cli": "^7.15.7",
|
|
21
22
|
"@babel/core": "^7.15.5",
|
|
22
23
|
"@babel/polyfill": "^7.12.1",
|
|
23
24
|
"@babel/preset-env": "^7.15.6",
|
|
24
|
-
"anme": "^1.0.0"
|
|
25
|
-
|
|
25
|
+
"anme": "^1.0.0"
|
|
26
|
+
|
|
26
27
|
}
|
|
27
28
|
}
|
|
@@ -1,78 +1,76 @@
|
|
|
1
1
|
import React, { useState, useRef, useEffect } from 'react';
|
|
2
2
|
import cn from 'classnames';
|
|
3
3
|
import { Check, ChevronDown, ChevronUp } from 'react-feather';
|
|
4
|
-
import Label from '../Label/Label';
|
|
5
4
|
|
|
6
5
|
import './Dropdown.scss';
|
|
7
6
|
|
|
8
7
|
const RC = 'dropdown';
|
|
9
8
|
|
|
10
|
-
const Dropdown = ({ options, value, error, onChange, placeholder, className, isSearchable, entity }) => {
|
|
9
|
+
const Dropdown = ({ options = [], value, error, onChange, placeholder, className, isSearchable, entity }) => {
|
|
11
10
|
const [isOpen, setIsOpen] = useState(false);
|
|
12
11
|
const [searchValue, setSearchValue] = useState('');
|
|
13
12
|
const dropdownRef = useRef(null);
|
|
14
|
-
|
|
13
|
+
if (!options) return null;
|
|
15
14
|
const filteredGroups = options
|
|
16
|
-
.filter(
|
|
17
|
-
.map(
|
|
18
|
-
.filter(
|
|
15
|
+
.filter(item => item.items?.length)
|
|
16
|
+
.map(item => ({ ...item, items: item.items.filter(el => el?.label?.toLowerCase().includes(searchValue?.toLowerCase() || '')) }))
|
|
17
|
+
.filter(item => item.items?.length > 0);
|
|
19
18
|
|
|
20
19
|
const filteredItems = options
|
|
21
|
-
.filter(
|
|
22
|
-
.filter(
|
|
20
|
+
.filter(item => !item.items?.length)
|
|
21
|
+
.filter(item => item?.label?.toLowerCase().includes(searchValue?.toLowerCase() || ''));
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
const filteredOptions = [...filteredItems, ...filteredGroups];
|
|
25
24
|
|
|
26
25
|
const modalBtnTrigger = entity && entity !== '' && typeof entity === 'string';
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
const onChangeHandler = item => {
|
|
27
|
+
setIsOpen(false);
|
|
28
|
+
setSearchValue(null);
|
|
29
|
+
onChange(item.value);
|
|
30
|
+
};
|
|
31
|
+
// decorator
|
|
32
|
+
const getDepends = getDependsTrigger => {
|
|
33
|
+
const newOnChange = e => {
|
|
34
|
+
if (e.value === 'open_modal') {
|
|
31
35
|
onChange('open_modal');
|
|
32
36
|
} else {
|
|
33
|
-
onChangeHandler(
|
|
37
|
+
onChangeHandler(e);
|
|
34
38
|
}
|
|
35
39
|
};
|
|
36
40
|
|
|
37
|
-
//add pseudo option
|
|
41
|
+
// add pseudo option
|
|
38
42
|
const newOptions = [
|
|
39
43
|
{
|
|
40
|
-
label:
|
|
44
|
+
label: `New ${entity}`,
|
|
41
45
|
value: 'open_modal',
|
|
42
|
-
className: 'dropdown__list-item--modal'
|
|
46
|
+
className: 'dropdown__list-item--modal'
|
|
43
47
|
},
|
|
44
|
-
...filteredOptions
|
|
48
|
+
...filteredOptions
|
|
45
49
|
];
|
|
46
50
|
|
|
47
51
|
return {
|
|
48
|
-
onChange:
|
|
49
|
-
options:
|
|
52
|
+
onChange: changeItem => (getDependsTrigger ? newOnChange(changeItem) : onChangeHandler(changeItem)),
|
|
53
|
+
options: getDependsTrigger ? newOptions : options
|
|
50
54
|
};
|
|
51
55
|
};
|
|
52
56
|
|
|
53
|
-
const handleClickOutside =
|
|
57
|
+
const handleClickOutside = event => {
|
|
54
58
|
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
55
59
|
setIsOpen(false);
|
|
56
60
|
setSearchValue(null);
|
|
57
61
|
}
|
|
58
62
|
};
|
|
59
63
|
|
|
60
|
-
const
|
|
61
|
-
setIsOpen(false);
|
|
62
|
-
setSearchValue(null);
|
|
63
|
-
onChange(item.value);
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const onSearchHandler = (name) => {
|
|
64
|
+
const onSearchHandler = name => {
|
|
67
65
|
setSearchValue(name);
|
|
68
66
|
};
|
|
69
67
|
|
|
70
|
-
const hightlightedText =
|
|
71
|
-
searchValue ? text?.replace(new RegExp(searchValue, 'i'),
|
|
68
|
+
const hightlightedText = text =>
|
|
69
|
+
searchValue ? text?.replace(new RegExp(searchValue, 'i'), match => `<span class="bg--yellow">${match}</span>`) : text;
|
|
72
70
|
|
|
73
71
|
const depend = getDepends(modalBtnTrigger);
|
|
74
72
|
|
|
75
|
-
const getMarkupForElement =
|
|
73
|
+
const getMarkupForElement = item =>
|
|
76
74
|
item.label.toLowerCase().includes(searchValue?.toLowerCase() || '') ? (
|
|
77
75
|
<button
|
|
78
76
|
key={item.value}
|
|
@@ -92,17 +90,16 @@ const Dropdown = ({ options, value, error, onChange, placeholder, className, isS
|
|
|
92
90
|
return () => document.removeEventListener('click', handleClickOutside, true);
|
|
93
91
|
}, [value]);
|
|
94
92
|
|
|
95
|
-
const filteredOptionList =
|
|
93
|
+
const filteredOptionList = filteredOption =>
|
|
96
94
|
filteredOption.items?.length > 0 ? (
|
|
97
95
|
<div key={filteredOption.value} className={`${RC}-group`}>
|
|
98
96
|
<div className={`${RC}-group__name`}>{filteredOption.label}</div>
|
|
99
|
-
{filteredOption.items.map(
|
|
97
|
+
{filteredOption.items.map(el => getMarkupForElement(el))}
|
|
100
98
|
</div>
|
|
101
99
|
) : null;
|
|
102
100
|
|
|
103
101
|
const selectedLabel =
|
|
104
|
-
options.find(
|
|
105
|
-
options.reduce((acc, item) => acc || item.items?.find((el) => el.value === value)?.label, null);
|
|
102
|
+
options.find(el => el.value === value)?.label || options.reduce((acc, item) => acc || item.items?.find(el => el.value === value)?.label, null);
|
|
106
103
|
|
|
107
104
|
return (
|
|
108
105
|
<div className={cn(RC, className)} ref={dropdownRef}>
|
|
@@ -113,9 +110,9 @@ const Dropdown = ({ options, value, error, onChange, placeholder, className, isS
|
|
|
113
110
|
{isSearchable ? (
|
|
114
111
|
<input
|
|
115
112
|
className={`${RC}__input`}
|
|
116
|
-
value={searchValue || filteredOptions.find(el => el.value === value)?.label
|
|
117
|
-
onChange={
|
|
118
|
-
onSearchHandler(e.target.value)
|
|
113
|
+
value={searchValue || filteredOptions.find(el => el.value === value)?.label || ''}
|
|
114
|
+
onChange={e => {
|
|
115
|
+
onSearchHandler(e.target.value);
|
|
119
116
|
}}
|
|
120
117
|
placeholder={placeholder}
|
|
121
118
|
onFocus={e => {
|
|
@@ -132,7 +129,7 @@ const Dropdown = ({ options, value, error, onChange, placeholder, className, isS
|
|
|
132
129
|
</button>
|
|
133
130
|
{isOpen && filteredOptions.length > 0 && (
|
|
134
131
|
<div className={`${RC}__list`}>
|
|
135
|
-
{depend.options.map(
|
|
132
|
+
{depend.options.map(filteredOption =>
|
|
136
133
|
filteredOption.items?.length ? filteredOptionList(filteredOption) : getMarkupForElement(filteredOption)
|
|
137
134
|
)}
|
|
138
135
|
</div>
|
|
@@ -1,64 +1,113 @@
|
|
|
1
1
|
import React, { useState, useEffect, useRef } from 'react';
|
|
2
2
|
import cn from 'classnames';
|
|
3
|
-
import { Minus, Plus } from 'react-feather';
|
|
4
3
|
import InputMask from 'react-input-mask';
|
|
4
|
+
import { KEYBOARD_SERVICE_KEYS } from '../../../Constants/index.constants';
|
|
5
|
+
import { formatInput } from '../../../Functions/inputExecutor';
|
|
5
6
|
|
|
6
7
|
import './Input.scss';
|
|
7
8
|
|
|
8
9
|
const Input = ({
|
|
9
10
|
onChange,
|
|
11
|
+
onBlur,
|
|
12
|
+
onFocus,
|
|
13
|
+
onKeyUp,
|
|
14
|
+
isNotBlinkErrors,
|
|
15
|
+
isPriceInput,
|
|
16
|
+
isOnlyNumber,
|
|
17
|
+
isOnlyString,
|
|
18
|
+
isTwoDigitAfterDot,
|
|
10
19
|
disabled,
|
|
11
20
|
withDelete,
|
|
12
|
-
isNumeric,
|
|
13
|
-
numStep = 1,
|
|
14
|
-
min = 0,
|
|
15
|
-
max,
|
|
16
21
|
value,
|
|
17
22
|
placeholder,
|
|
18
23
|
className,
|
|
19
24
|
type = 'text',
|
|
20
|
-
onBlur,
|
|
21
|
-
onFocus,
|
|
22
|
-
onKeyUp,
|
|
23
25
|
mask,
|
|
24
26
|
maskChar,
|
|
25
27
|
formatChars,
|
|
26
28
|
error,
|
|
27
29
|
icon,
|
|
28
30
|
symbolsLimit,
|
|
31
|
+
blinkTime
|
|
29
32
|
}) => {
|
|
33
|
+
const DEFAULT_BLINK_TIME = 100;
|
|
30
34
|
// STATES
|
|
31
35
|
const [isFocused, setIsFocused] = useState(false);
|
|
32
36
|
const [isEditing, setEditing] = useState(false);
|
|
33
37
|
const inputRef = useRef(null);
|
|
38
|
+
const previousValueRef = useRef(value);
|
|
39
|
+
const [isAttemptToChange, setIsAttemptToChange] = useState(false);
|
|
40
|
+
const [isToHighlightError, setIsToHighlightError] = useState(false);
|
|
41
|
+
|
|
42
|
+
const { onlyNumbers, onlyString } = formatInput;
|
|
43
|
+
const { addCommas, removeComma } = formatInput.priceInput;
|
|
34
44
|
// HANDLES
|
|
35
45
|
const handle = {
|
|
36
|
-
change: e => {
|
|
46
|
+
change: (e) => {
|
|
37
47
|
let inputValue = e.target ? e.target.value : e;
|
|
38
|
-
if (
|
|
39
|
-
inputValue =
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
if (symbolsLimit && inputValue.length > +symbolsLimit) {
|
|
49
|
+
inputValue = inputValue.substring(0, +symbolsLimit);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (isOnlyNumber && !isTwoDigitAfterDot)
|
|
53
|
+
inputValue = onlyNumbers(inputValue);
|
|
54
|
+
if (isTwoDigitAfterDot) inputValue = onlyNumbers(inputValue, true);
|
|
55
|
+
if (isOnlyString) inputValue = onlyString(inputValue);
|
|
56
|
+
|
|
44
57
|
onChange(inputValue.toString());
|
|
45
58
|
},
|
|
46
59
|
toggleEdit: () => {
|
|
47
60
|
setEditing(!isEditing);
|
|
48
61
|
onChange('');
|
|
49
62
|
},
|
|
50
|
-
focus: e => {
|
|
63
|
+
focus: (e) => {
|
|
51
64
|
setIsFocused(true);
|
|
65
|
+
if (isPriceInput && isOnlyNumber && !isTwoDigitAfterDot)
|
|
66
|
+
onChange(removeComma(value));
|
|
67
|
+
|
|
52
68
|
if (onFocus) onFocus(e);
|
|
53
69
|
},
|
|
54
|
-
blur: e => {
|
|
70
|
+
blur: (e) => {
|
|
55
71
|
setIsFocused(false);
|
|
56
72
|
setEditing(false);
|
|
73
|
+
if (isPriceInput && isOnlyNumber && !isTwoDigitAfterDot) {
|
|
74
|
+
onChange(addCommas(value));
|
|
75
|
+
}
|
|
76
|
+
if (isTwoDigitAfterDot && !isPriceInput) {
|
|
77
|
+
onChange(cutOffsingleDot(value));
|
|
78
|
+
}
|
|
57
79
|
if (onBlur) onBlur(e);
|
|
58
80
|
},
|
|
59
|
-
keyUp:
|
|
81
|
+
keyUp: (e) => {
|
|
82
|
+
if (!isNotBlinkErrors) {
|
|
83
|
+
const changedValue = '' + (value ?? '');
|
|
84
|
+
const previousValue = '' + (previousValueRef.current ?? '');
|
|
85
|
+
const currentSet = (() => {
|
|
86
|
+
if (previousValue.length < changedValue.length)
|
|
87
|
+
return value.slice(previousValue.length - changedValue.length);
|
|
88
|
+
else return changedValue.includes(e.key) ? e.key : '';
|
|
89
|
+
})();
|
|
90
|
+
|
|
91
|
+
if (
|
|
92
|
+
!KEYBOARD_SERVICE_KEYS.includes(e.key) &&
|
|
93
|
+
changedValue === previousValue
|
|
94
|
+
)
|
|
95
|
+
setIsAttemptToChange(true);
|
|
96
|
+
|
|
97
|
+
console.log(changedValue, previousValue);
|
|
98
|
+
if (KEYBOARD_SERVICE_KEYS.includes(e.key) || !currentSet)
|
|
99
|
+
previousValueRef.current = value;
|
|
100
|
+
else previousValueRef.current = previousValue + currentSet[0];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (onKeyUp) onKeyUp(e.keyCode, e);
|
|
104
|
+
}
|
|
60
105
|
};
|
|
61
106
|
|
|
107
|
+
function cutOffsingleDot(value) {
|
|
108
|
+
return value.slice(-1) === '.' ? value.slice(0, -1) : value;
|
|
109
|
+
}
|
|
110
|
+
|
|
62
111
|
useEffect(() => {
|
|
63
112
|
if (isEditing) inputRef.current.focus();
|
|
64
113
|
}, [isEditing, isFocused]);
|
|
@@ -72,10 +121,8 @@ const Input = ({
|
|
|
72
121
|
onFocus: handle.focus,
|
|
73
122
|
onBlur: handle.blur,
|
|
74
123
|
onKeyUp: handle.keyUp,
|
|
75
|
-
min,
|
|
76
|
-
max,
|
|
77
124
|
...(maskChar ? { maskChar } : {}),
|
|
78
|
-
...(formatChars ? { formatChars } : {})
|
|
125
|
+
...(formatChars ? { formatChars } : {})
|
|
79
126
|
};
|
|
80
127
|
|
|
81
128
|
function renderInput() {
|
|
@@ -84,34 +131,37 @@ const Input = ({
|
|
|
84
131
|
}
|
|
85
132
|
|
|
86
133
|
return (
|
|
87
|
-
|
|
88
|
-
<input {...uniProps} ref={inputRef} type={isNumeric ? 'number' : type} />
|
|
89
|
-
{isNumeric && (
|
|
90
|
-
<div className="input__nums">
|
|
91
|
-
<button onClick={() => handle.change(value - numStep)} className={cn(`input__num-btn`, { disabled: value <= min })}>
|
|
92
|
-
<Minus />
|
|
93
|
-
</button>
|
|
94
|
-
<button onClick={() => handle.change(+value + +numStep)} className={cn(`input__num-btn`, { disabled: value >= max })}>
|
|
95
|
-
<Plus />
|
|
96
|
-
</button>
|
|
97
|
-
</div>
|
|
98
|
-
)}
|
|
99
|
-
</>
|
|
134
|
+
<input {...uniProps} ref={inputRef} type={isPriceInput ? 'text' : type} />
|
|
100
135
|
);
|
|
101
136
|
}
|
|
102
137
|
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
if (!isNotBlinkErrors && isAttemptToChange) {
|
|
140
|
+
setIsAttemptToChange(null);
|
|
141
|
+
setIsToHighlightError(true);
|
|
142
|
+
setTimeout(() => {
|
|
143
|
+
setIsToHighlightError(false);
|
|
144
|
+
}, blinkTime || DEFAULT_BLINK_TIME);
|
|
145
|
+
}
|
|
146
|
+
}, [isAttemptToChange]);
|
|
147
|
+
|
|
103
148
|
return (
|
|
104
149
|
<div
|
|
105
150
|
className={cn(
|
|
106
151
|
`input__wrap`,
|
|
107
152
|
{ [`input__wrap_focus`]: isFocused },
|
|
108
|
-
{ [`input__wrap_error`]: error },
|
|
153
|
+
{ [`input__wrap_error`]: error || isToHighlightError },
|
|
109
154
|
{ [`input__wrap_disabled`]: disabled }
|
|
110
155
|
)}
|
|
111
156
|
>
|
|
112
157
|
{renderInput()}
|
|
113
158
|
{icon}
|
|
114
|
-
{withDelete &&
|
|
159
|
+
{withDelete && (
|
|
160
|
+
<span
|
|
161
|
+
className={cn(`input__close`, { hidden: !value })}
|
|
162
|
+
onClick={handle.toggleEdit}
|
|
163
|
+
/>
|
|
164
|
+
)}
|
|
115
165
|
</div>
|
|
116
166
|
);
|
|
117
167
|
};
|