intelicoreact 0.0.8 → 0.0.9
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 +43 -19
- package/dist/Atomic/FormElements/Dropdown/Dropdown.scss +6 -0
- package/dist/Atomic/FormElements/Dropdown/Dropdown.stories.js +34 -7
- package/dist/Atomic/FormElements/Dropdown/components/DropdownLoader.js +20 -0
- package/dist/Atomic/FormElements/Dropdown/components/Loader.scss +57 -0
- package/dist/Atomic/FormElements/Input/Input.js +42 -18
- package/dist/Atomic/FormElements/Input/Input.stories.js +4 -0
- package/dist/Atomic/FormElements/InputCalendar/InputCalendar.js +33 -31
- package/dist/Atomic/FormElements/InputCalendar/InputCalendar.stories.js +29 -19
- package/dist/Atomic/FormElements/InputDateRange/InputDateRange.js +8 -2
- package/dist/Atomic/FormElements/InputDateRange/InputDateRange.scss +2 -4
- package/dist/Atomic/FormElements/InputDateRange/InputDateRange.stories.js +2 -0
- package/dist/Atomic/FormElements/InputDateRange/components/Datepicker.js +35 -20
- package/dist/Atomic/FormElements/InputDateRange/components/OpenedPart.js +8 -2
- package/dist/Atomic/FormElements/InputDateRange/dependencies.js +1 -1
- package/dist/Atomic/FormElements/NumericInput/NumericInput.js +125 -87
- package/dist/Atomic/FormElements/NumericInput/NumericInput.stories.js +6 -10
- package/dist/Atomic/FormElements/RangeCalendar/RangeCalendar.js +3 -1
- package/dist/Atomic/FormElements/RangeCalendar/RangeCalendar.scss +4 -4
- package/dist/Atomic/UI/Calendar/Calendar.js +6 -4
- package/dist/Atomic/UI/Calendar/Calendar.scss +19 -3
- package/dist/Functions/inputExecutor.js +1 -1
- package/package.json +2 -3
- package/src/Atomic/FormElements/Dropdown/Dropdown.js +66 -35
- package/src/Atomic/FormElements/Dropdown/Dropdown.scss +6 -0
- package/src/Atomic/FormElements/Dropdown/Dropdown.stories.js +22 -8
- package/src/Atomic/FormElements/Dropdown/components/DropdownLoader.js +16 -0
- package/src/Atomic/FormElements/Dropdown/components/Loader.scss +57 -0
- package/src/Atomic/FormElements/Input/Input.js +56 -39
- package/src/Atomic/FormElements/Input/Input.stories.js +4 -0
- package/src/Atomic/FormElements/InputCalendar/InputCalendar.js +18 -17
- package/src/Atomic/FormElements/InputCalendar/InputCalendar.stories.js +17 -14
- package/src/Atomic/FormElements/InputDateRange/InputDateRange.js +5 -0
- package/src/Atomic/FormElements/InputDateRange/InputDateRange.scss +2 -4
- package/src/Atomic/FormElements/InputDateRange/InputDateRange.stories.js +2 -0
- package/src/Atomic/FormElements/InputDateRange/components/Datepicker.js +41 -20
- package/src/Atomic/FormElements/InputDateRange/components/OpenedPart.js +5 -1
- package/src/Atomic/FormElements/InputDateRange/dependencies.js +1 -1
- package/src/Atomic/FormElements/NumericInput/NumericInput.js +107 -64
- package/src/Atomic/FormElements/NumericInput/NumericInput.stories.js +6 -22
- package/src/Atomic/FormElements/RangeCalendar/RangeCalendar.js +1 -1
- package/src/Atomic/FormElements/RangeCalendar/RangeCalendar.scss +4 -4
- package/src/Atomic/UI/Calendar/Calendar.js +3 -3
- package/src/Atomic/UI/Calendar/Calendar.scss +19 -3
- package/src/Functions/inputExecutor.js +6 -15
|
@@ -1,36 +1,40 @@
|
|
|
1
|
-
import React, { useState, useRef, useEffect } from 'react';
|
|
1
|
+
import React, { useState, useRef, useEffect, useCallback } from 'react';
|
|
2
2
|
import cn from 'classnames';
|
|
3
3
|
import { Check, ChevronDown, ChevronUp } from 'react-feather';
|
|
4
4
|
|
|
5
|
+
import DropdownLoader from './components/DropdownLoader';
|
|
6
|
+
|
|
5
7
|
import './Dropdown.scss';
|
|
6
8
|
|
|
7
9
|
const RC = 'dropdown';
|
|
8
10
|
|
|
9
|
-
const Dropdown = ({ options = [], value, error, onChange, placeholder, className, isSearchable, entity }) => {
|
|
11
|
+
const Dropdown = ({ options = [], value, error, disabled, onChange, placeholder, className, isSearchable, entity, scrollReactionObj }) => {
|
|
10
12
|
const [isOpen, setIsOpen] = useState(false);
|
|
11
|
-
const [searchValue, setSearchValue] = useState(
|
|
13
|
+
const [searchValue, setSearchValue] = useState();
|
|
12
14
|
const dropdownRef = useRef(null);
|
|
15
|
+
const dropdownListRef = useRef(null);
|
|
16
|
+
|
|
13
17
|
if (!options) return null;
|
|
14
18
|
const filteredGroups = options
|
|
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
|
+
.filter((item) => item.items?.length)
|
|
20
|
+
.map((item) => ({ ...item, items: item.items.filter((el) => el?.label?.toLowerCase().includes(searchValue?.toLowerCase() || '')) }))
|
|
21
|
+
.filter((item) => item.items?.length > 0);
|
|
18
22
|
|
|
19
23
|
const filteredItems = options
|
|
20
|
-
.filter(item => !item.items?.length)
|
|
21
|
-
.filter(item => item?.label?.toLowerCase().includes(searchValue?.toLowerCase() || ''));
|
|
24
|
+
.filter((item) => !item.items?.length)
|
|
25
|
+
.filter((item) => item?.label?.toLowerCase().includes(searchValue?.toLowerCase() || ''));
|
|
22
26
|
|
|
23
27
|
const filteredOptions = [...filteredItems, ...filteredGroups];
|
|
24
28
|
|
|
25
29
|
const modalBtnTrigger = entity && entity !== '' && typeof entity === 'string';
|
|
26
|
-
const onChangeHandler = item => {
|
|
30
|
+
const onChangeHandler = (item) => {
|
|
27
31
|
setIsOpen(false);
|
|
28
32
|
setSearchValue(null);
|
|
29
33
|
onChange(item.value);
|
|
30
34
|
};
|
|
31
35
|
// decorator
|
|
32
|
-
const getDepends = getDependsTrigger => {
|
|
33
|
-
const newOnChange = e => {
|
|
36
|
+
const getDepends = (getDependsTrigger) => {
|
|
37
|
+
const newOnChange = (e) => {
|
|
34
38
|
if (e.value === 'open_modal') {
|
|
35
39
|
onChange('open_modal');
|
|
36
40
|
} else {
|
|
@@ -43,34 +47,34 @@ const Dropdown = ({ options = [], value, error, onChange, placeholder, className
|
|
|
43
47
|
{
|
|
44
48
|
label: `New ${entity}`,
|
|
45
49
|
value: 'open_modal',
|
|
46
|
-
className: 'dropdown__list-item--modal'
|
|
50
|
+
className: 'dropdown__list-item--modal',
|
|
47
51
|
},
|
|
48
|
-
...filteredOptions
|
|
52
|
+
...filteredOptions,
|
|
49
53
|
];
|
|
50
54
|
|
|
51
55
|
return {
|
|
52
|
-
onChange: changeItem => (getDependsTrigger ? newOnChange(changeItem) : onChangeHandler(changeItem)),
|
|
53
|
-
options: getDependsTrigger ? newOptions : options
|
|
56
|
+
onChange: (changeItem) => (getDependsTrigger ? newOnChange(changeItem) : onChangeHandler(changeItem)),
|
|
57
|
+
options: getDependsTrigger ? newOptions : options,
|
|
54
58
|
};
|
|
55
59
|
};
|
|
56
60
|
|
|
57
|
-
const handleClickOutside = event => {
|
|
61
|
+
const handleClickOutside = (event) => {
|
|
58
62
|
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
59
63
|
setIsOpen(false);
|
|
60
64
|
setSearchValue(null);
|
|
61
65
|
}
|
|
62
66
|
};
|
|
63
67
|
|
|
64
|
-
const onSearchHandler = name => {
|
|
68
|
+
const onSearchHandler = (name) => {
|
|
65
69
|
setSearchValue(name);
|
|
66
70
|
};
|
|
67
71
|
|
|
68
|
-
const hightlightedText = text =>
|
|
69
|
-
searchValue ? text?.replace(new RegExp(searchValue, 'i'), match => `<span class="bg--yellow">${match}</span>`) : text;
|
|
72
|
+
const hightlightedText = (text) =>
|
|
73
|
+
searchValue ? text?.replace(new RegExp(searchValue, 'i'), (match) => `<span class="bg--yellow">${match}</span>`) : text;
|
|
70
74
|
|
|
71
75
|
const depend = getDepends(modalBtnTrigger);
|
|
72
76
|
|
|
73
|
-
const getMarkupForElement = item =>
|
|
77
|
+
const getMarkupForElement = (item) =>
|
|
74
78
|
item.label.toLowerCase().includes(searchValue?.toLowerCase() || '') ? (
|
|
75
79
|
<button
|
|
76
80
|
key={item.value}
|
|
@@ -84,25 +88,51 @@ const Dropdown = ({ options = [], value, error, onChange, placeholder, className
|
|
|
84
88
|
</button>
|
|
85
89
|
) : null;
|
|
86
90
|
|
|
87
|
-
|
|
88
|
-
if (!value) setSearchValue(null);
|
|
89
|
-
document.addEventListener('click', handleClickOutside, true);
|
|
90
|
-
return () => document.removeEventListener('click', handleClickOutside, true);
|
|
91
|
-
}, [value]);
|
|
92
|
-
|
|
93
|
-
const filteredOptionList = filteredOption =>
|
|
91
|
+
const filteredOptionList = (filteredOption) =>
|
|
94
92
|
filteredOption.items?.length > 0 ? (
|
|
95
93
|
<div key={filteredOption.value} className={`${RC}-group`}>
|
|
96
94
|
<div className={`${RC}-group__name`}>{filteredOption.label}</div>
|
|
97
|
-
{filteredOption.items.map(el => getMarkupForElement(el))}
|
|
95
|
+
{filteredOption.items.map((el) => getMarkupForElement(el))}
|
|
98
96
|
</div>
|
|
99
97
|
) : null;
|
|
100
98
|
|
|
101
99
|
const selectedLabel =
|
|
102
|
-
options.find(el => el.value === value)?.label ||
|
|
100
|
+
options.find((el) => el.value === value)?.label ||
|
|
101
|
+
options.reduce((acc, item) => acc || item.items?.find((el) => el.value === value)?.label, null);
|
|
102
|
+
|
|
103
|
+
const doScrollCallback = useCallback(
|
|
104
|
+
(e) => {
|
|
105
|
+
const { callback, isWithAnyScrolling } = scrollReactionObj;
|
|
106
|
+
if (callback && typeof callback === 'function') {
|
|
107
|
+
if (isWithAnyScrolling) callback(e);
|
|
108
|
+
else if (e.target.clientHeight + e.target.scrollTop >= e.target.scrollHeight) callback(e);
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
[filteredOptions]
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
if (!value) setSearchValue(null);
|
|
116
|
+
document.addEventListener('click', handleClickOutside, true);
|
|
117
|
+
return () => document.removeEventListener('click', handleClickOutside, true);
|
|
118
|
+
}, [value]);
|
|
119
|
+
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
if (scrollReactionObj && typeof scrollReactionObj === 'object' && isOpen && dropdownListRef && dropdownListRef.current) {
|
|
122
|
+
dropdownListRef.current.addEventListener('scroll', doScrollCallback);
|
|
123
|
+
}
|
|
124
|
+
return () => {
|
|
125
|
+
if (scrollReactionObj && typeof scrollReactionObj === 'object') removeEventListener('scroll', doScrollCallback);
|
|
126
|
+
};
|
|
127
|
+
}, [isOpen, dropdownListRef]);
|
|
103
128
|
|
|
104
129
|
return (
|
|
105
|
-
<div
|
|
130
|
+
<div
|
|
131
|
+
className={cn(RC, className, {
|
|
132
|
+
disabled: disabled,
|
|
133
|
+
})}
|
|
134
|
+
ref={dropdownRef}
|
|
135
|
+
>
|
|
106
136
|
<button
|
|
107
137
|
className={`${RC}__trigger input__wrap ${!value ? 'placeholder' : ''} ${error ? 'error' : ''}`}
|
|
108
138
|
onClick={() => (!isSearchable ? setIsOpen(!isOpen) : null)}
|
|
@@ -110,12 +140,12 @@ const Dropdown = ({ options = [], value, error, onChange, placeholder, className
|
|
|
110
140
|
{isSearchable ? (
|
|
111
141
|
<input
|
|
112
142
|
className={`${RC}__input`}
|
|
113
|
-
value={searchValue ||
|
|
114
|
-
onChange={e => {
|
|
143
|
+
value={searchValue || selectedLabel || ''}
|
|
144
|
+
onChange={(e) => {
|
|
115
145
|
onSearchHandler(e.target.value);
|
|
116
146
|
}}
|
|
117
147
|
placeholder={placeholder}
|
|
118
|
-
onFocus={e => {
|
|
148
|
+
onFocus={(e) => {
|
|
119
149
|
e.target.select();
|
|
120
150
|
setIsOpen(true);
|
|
121
151
|
}}
|
|
@@ -128,10 +158,11 @@ const Dropdown = ({ options = [], value, error, onChange, placeholder, className
|
|
|
128
158
|
</span>
|
|
129
159
|
</button>
|
|
130
160
|
{isOpen && filteredOptions.length > 0 && (
|
|
131
|
-
<div className={`${RC}__list`}>
|
|
132
|
-
{depend.options.map(filteredOption =>
|
|
161
|
+
<div className={`${RC}__list`} ref={dropdownListRef}>
|
|
162
|
+
{depend.options.map((filteredOption) =>
|
|
133
163
|
filteredOption.items?.length ? filteredOptionList(filteredOption) : getMarkupForElement(filteredOption)
|
|
134
164
|
)}
|
|
165
|
+
{disabled && isOpen && <DropdownLoader />}
|
|
135
166
|
</div>
|
|
136
167
|
)}
|
|
137
168
|
</div>
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
&__list {
|
|
48
|
+
position: relative;
|
|
48
49
|
background: #ffffff;
|
|
49
50
|
border: 1px solid #e2e5ec;
|
|
50
51
|
box-shadow: 0 5px 20px rgb(0 0 0 / 15%);
|
|
@@ -177,4 +178,9 @@
|
|
|
177
178
|
font-size: 10px;
|
|
178
179
|
color: $color--secondary;
|
|
179
180
|
}
|
|
181
|
+
|
|
182
|
+
&.disabled {
|
|
183
|
+
pointer-events: none;
|
|
184
|
+
opacity: 0.5;
|
|
185
|
+
}
|
|
180
186
|
}
|
|
@@ -20,20 +20,34 @@ export default {
|
|
|
20
20
|
},
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
-
const
|
|
23
|
+
const blockStyles = {
|
|
24
|
+
display: 'flex',
|
|
25
|
+
flexFlow: 'row no-wrap',
|
|
26
|
+
alignItems: 'center',
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const buttonStyles = {
|
|
24
30
|
border: 'solid 1px #000',
|
|
25
|
-
padding: '5px'
|
|
31
|
+
padding: '5px',
|
|
32
|
+
margin: '0 0 0 50px',
|
|
26
33
|
};
|
|
27
34
|
|
|
28
35
|
const Template = (args) => {
|
|
29
|
-
const [value, setValue] = useState(
|
|
36
|
+
const [value, setValue] = useState(args.value);
|
|
37
|
+
const [disabled, setDisabled] = useState(false);
|
|
30
38
|
return (
|
|
31
|
-
|
|
32
|
-
<div style={{ width: 200 }}>
|
|
33
|
-
<Dropdown {...args} value={value} onChange={setValue} />
|
|
39
|
+
<div style={blockStyles}>
|
|
40
|
+
<div key="dropdown" style={{ width: 200 }}>
|
|
41
|
+
<Dropdown {...args} value={value} onChange={setValue} disabled={disabled} scrollReactionObj={{ callback: (e) => setDisabled(true) }} />
|
|
34
42
|
</div>
|
|
35
|
-
<button style={buttonStyles} className=
|
|
36
|
-
|
|
43
|
+
<button key="reset" style={buttonStyles} className="mt10" onClick={() => setValue('')}>
|
|
44
|
+
Reset
|
|
45
|
+
</button>
|
|
46
|
+
|
|
47
|
+
<button key="enable/disable" style={buttonStyles} className="mt10" onClick={() => setDisabled(!disabled)}>
|
|
48
|
+
{disabled ? 'enable' : 'disable'}
|
|
49
|
+
</button>
|
|
50
|
+
</div>
|
|
37
51
|
);
|
|
38
52
|
};
|
|
39
53
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import './Loader.scss';
|
|
2
|
+
|
|
3
|
+
const DropdownLoader = function ({ variant }) {
|
|
4
|
+
return (
|
|
5
|
+
<div className="dropdown-loader-box j5">
|
|
6
|
+
<div className={`lds-ring${variant === 'little' ? ' lds-ring_little' : ''}`}>
|
|
7
|
+
<div />
|
|
8
|
+
<div />
|
|
9
|
+
<div />
|
|
10
|
+
<div />
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default DropdownLoader;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
@mixin fill-parent {
|
|
2
|
+
left: 0;
|
|
3
|
+
top: 0;
|
|
4
|
+
width: 100%;
|
|
5
|
+
height: 100%;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.dropdown-loader-box {
|
|
9
|
+
position: absolute;
|
|
10
|
+
@include fill-parent;
|
|
11
|
+
background: #fff;
|
|
12
|
+
opacity: 0.1;
|
|
13
|
+
z-index: 100;
|
|
14
|
+
}
|
|
15
|
+
.lds-ring {
|
|
16
|
+
display: inline-block;
|
|
17
|
+
position: relative;
|
|
18
|
+
width: 100px;
|
|
19
|
+
height: 100px;
|
|
20
|
+
}
|
|
21
|
+
.lds-ring.lds-ring_little {
|
|
22
|
+
width: 20px;
|
|
23
|
+
height: 20px;
|
|
24
|
+
}
|
|
25
|
+
.lds-ring div {
|
|
26
|
+
box-sizing: border-box;
|
|
27
|
+
display: block;
|
|
28
|
+
position: absolute;
|
|
29
|
+
width: 84px;
|
|
30
|
+
height: 84px;
|
|
31
|
+
margin: 8px;
|
|
32
|
+
border: 8px solid #000;
|
|
33
|
+
border-radius: 50%;
|
|
34
|
+
animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
|
|
35
|
+
border-color: #000 transparent transparent transparent;
|
|
36
|
+
}
|
|
37
|
+
.lds-ring_little div {
|
|
38
|
+
width: 20px;
|
|
39
|
+
height: 20px;
|
|
40
|
+
}
|
|
41
|
+
.lds-ring div:nth-child(1) {
|
|
42
|
+
animation-delay: -0.45s;
|
|
43
|
+
}
|
|
44
|
+
.lds-ring div:nth-child(2) {
|
|
45
|
+
animation-delay: -0.3s;
|
|
46
|
+
}
|
|
47
|
+
.lds-ring div:nth-child(3) {
|
|
48
|
+
animation-delay: -0.15s;
|
|
49
|
+
}
|
|
50
|
+
@keyframes lds-ring {
|
|
51
|
+
0% {
|
|
52
|
+
transform: rotate(0deg);
|
|
53
|
+
}
|
|
54
|
+
100% {
|
|
55
|
+
transform: rotate(360deg);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -28,7 +28,8 @@ const Input = ({
|
|
|
28
28
|
error,
|
|
29
29
|
icon,
|
|
30
30
|
symbolsLimit,
|
|
31
|
-
blinkTime
|
|
31
|
+
blinkTime,
|
|
32
|
+
isFocusDefault = false,
|
|
32
33
|
}) => {
|
|
33
34
|
const DEFAULT_BLINK_TIME = 100;
|
|
34
35
|
// STATES
|
|
@@ -41,6 +42,8 @@ const Input = ({
|
|
|
41
42
|
|
|
42
43
|
const { onlyNumbers, onlyString } = formatInput;
|
|
43
44
|
const { addCommas, removeComma } = formatInput.priceInput;
|
|
45
|
+
const isUseErrorsBlink = !isNotBlinkErrors && !mask;
|
|
46
|
+
|
|
44
47
|
// HANDLES
|
|
45
48
|
const handle = {
|
|
46
49
|
change: (e) => {
|
|
@@ -49,8 +52,7 @@ const Input = ({
|
|
|
49
52
|
inputValue = inputValue.substring(0, +symbolsLimit);
|
|
50
53
|
}
|
|
51
54
|
|
|
52
|
-
if (isOnlyNumber && !isTwoDigitAfterDot)
|
|
53
|
-
inputValue = onlyNumbers(inputValue);
|
|
55
|
+
if (isOnlyNumber && !isTwoDigitAfterDot) inputValue = onlyNumbers(inputValue);
|
|
54
56
|
if (isTwoDigitAfterDot) inputValue = onlyNumbers(inputValue, true);
|
|
55
57
|
if (isOnlyString) inputValue = onlyString(inputValue);
|
|
56
58
|
|
|
@@ -62,50 +64,67 @@ const Input = ({
|
|
|
62
64
|
},
|
|
63
65
|
focus: (e) => {
|
|
64
66
|
setIsFocused(true);
|
|
65
|
-
if (isPriceInput && isOnlyNumber
|
|
66
|
-
onChange(removeComma(value));
|
|
67
|
+
if (isPriceInput && isOnlyNumber) onChange(removeComma(value));
|
|
67
68
|
|
|
68
69
|
if (onFocus) onFocus(e);
|
|
69
70
|
},
|
|
70
71
|
blur: (e) => {
|
|
71
72
|
setIsFocused(false);
|
|
72
73
|
setEditing(false);
|
|
73
|
-
if (
|
|
74
|
-
onChange(addCommas(value));
|
|
75
|
-
}
|
|
76
|
-
if (isTwoDigitAfterDot && !isPriceInput) {
|
|
74
|
+
if (isTwoDigitAfterDot) {
|
|
77
75
|
onChange(cutOffsingleDot(value));
|
|
78
76
|
}
|
|
77
|
+
if (isPriceInput && isOnlyNumber) {
|
|
78
|
+
onChange(addCommas(value));
|
|
79
|
+
}
|
|
79
80
|
if (onBlur) onBlur(e);
|
|
80
81
|
},
|
|
81
82
|
keyUp: (e) => {
|
|
82
|
-
if (
|
|
83
|
+
if (isUseErrorsBlink) {
|
|
83
84
|
const changedValue = '' + (value ?? '');
|
|
84
85
|
const previousValue = '' + (previousValueRef.current ?? '');
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
86
|
+
|
|
87
|
+
const short = previousValue.length <= changedValue.length ? previousValue : changedValue;
|
|
88
|
+
const long = previousValue.length > changedValue.length ? previousValue : changedValue;
|
|
89
|
+
|
|
90
|
+
const infoAboutDifferencesSameness = short.split('').reduce(
|
|
91
|
+
(acc, symbol, idx) => {
|
|
92
|
+
if (acc.countOn && symbol === long[idx]) acc.same.push(symbol);
|
|
93
|
+
else {
|
|
94
|
+
acc.countOn = false;
|
|
95
|
+
acc.differences.push([idx, symbol]);
|
|
96
|
+
}
|
|
97
|
+
return acc;
|
|
98
|
+
},
|
|
99
|
+
{ same: [], countOn: true, differences: [] }
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const samePart = infoAboutDifferencesSameness.same.join('');
|
|
103
|
+
const differencesLength = infoAboutDifferencesSameness.differences.length;
|
|
104
|
+
const currentSet = changedValue.replace(samePart, '');
|
|
105
|
+
|
|
106
|
+
const getNext = (inputPartToAdd, correctedSamePart) => {
|
|
107
|
+
const partToAdd = inputPartToAdd || currentSet;
|
|
108
|
+
const currentSamePart = correctedSamePart || samePart;
|
|
109
|
+
return changedValue.includes(e.key) && e.key !== changedValue[changedValue.length - 1]
|
|
110
|
+
? currentSamePart + (partToAdd[0] || '')
|
|
111
|
+
: changedValue;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
if (!KEYBOARD_SERVICE_KEYS.includes(e.key) && changedValue === previousValue)
|
|
115
|
+
setIsAttemptToChange(!(!differencesLength && e.key === changedValue[changedValue.length - 2]));
|
|
116
|
+
|
|
117
|
+
if (!previousValueRef.current || KEYBOARD_SERVICE_KEYS.includes(e.key)) previousValueRef.current = getNext();
|
|
118
|
+
else if (changedValue === samePart) previousValueRef.current = getNext(changedValue, changedValue.slice(0, -1));
|
|
119
|
+
else previousValueRef.current = getNext();
|
|
101
120
|
}
|
|
102
121
|
|
|
103
122
|
if (onKeyUp) onKeyUp(e.keyCode, e);
|
|
104
|
-
}
|
|
123
|
+
},
|
|
105
124
|
};
|
|
106
125
|
|
|
107
126
|
function cutOffsingleDot(value) {
|
|
108
|
-
return value.slice(-1) === '.' ? value.slice(0, -1) : value;
|
|
127
|
+
return value.toString().slice(-1) === '.' ? value.slice(0, -1) : value;
|
|
109
128
|
}
|
|
110
129
|
|
|
111
130
|
useEffect(() => {
|
|
@@ -122,7 +141,7 @@ const Input = ({
|
|
|
122
141
|
onBlur: handle.blur,
|
|
123
142
|
onKeyUp: handle.keyUp,
|
|
124
143
|
...(maskChar ? { maskChar } : {}),
|
|
125
|
-
...(formatChars ? { formatChars } : {})
|
|
144
|
+
...(formatChars ? { formatChars } : {}),
|
|
126
145
|
};
|
|
127
146
|
|
|
128
147
|
function renderInput() {
|
|
@@ -130,13 +149,11 @@ const Input = ({
|
|
|
130
149
|
return <InputMask {...uniProps} ref={inputRef} mask={mask} />;
|
|
131
150
|
}
|
|
132
151
|
|
|
133
|
-
return
|
|
134
|
-
<input {...uniProps} ref={inputRef} type={isPriceInput ? 'text' : type} />
|
|
135
|
-
);
|
|
152
|
+
return <input {...uniProps} ref={inputRef} type={isPriceInput ? 'text' : type} />;
|
|
136
153
|
}
|
|
137
154
|
|
|
138
155
|
useEffect(() => {
|
|
139
|
-
if (
|
|
156
|
+
if (isUseErrorsBlink && isAttemptToChange) {
|
|
140
157
|
setIsAttemptToChange(null);
|
|
141
158
|
setIsToHighlightError(true);
|
|
142
159
|
setTimeout(() => {
|
|
@@ -145,6 +162,11 @@ const Input = ({
|
|
|
145
162
|
}
|
|
146
163
|
}, [isAttemptToChange]);
|
|
147
164
|
|
|
165
|
+
useEffect(() => {
|
|
166
|
+
if (inputRef?.current && typeof isFocusDefault === 'boolean') setIsFocused(isFocusDefault);
|
|
167
|
+
setEditing(isFocusDefault);
|
|
168
|
+
}, [inputRef, isFocusDefault]);
|
|
169
|
+
|
|
148
170
|
return (
|
|
149
171
|
<div
|
|
150
172
|
className={cn(
|
|
@@ -156,12 +178,7 @@ const Input = ({
|
|
|
156
178
|
>
|
|
157
179
|
{renderInput()}
|
|
158
180
|
{icon}
|
|
159
|
-
{withDelete && (
|
|
160
|
-
<span
|
|
161
|
-
className={cn(`input__close`, { hidden: !value })}
|
|
162
|
-
onClick={handle.toggleEdit}
|
|
163
|
-
/>
|
|
164
|
-
)}
|
|
181
|
+
{withDelete && <span className={cn(`input__close`, { hidden: !value })} onClick={handle.toggleEdit} />}
|
|
165
182
|
</div>
|
|
166
183
|
);
|
|
167
184
|
};
|
|
@@ -29,6 +29,9 @@ export default {
|
|
|
29
29
|
isTwoDigitAfterDot: {
|
|
30
30
|
description: 'boolean - only two digits after dot'
|
|
31
31
|
},
|
|
32
|
+
isFocusDefault: {
|
|
33
|
+
description: 'boolean - if true, input will be focused on mount'
|
|
34
|
+
},
|
|
32
35
|
placeholder: {
|
|
33
36
|
description: 'text'
|
|
34
37
|
},
|
|
@@ -76,6 +79,7 @@ export const InputTemplate = Template.bind({});
|
|
|
76
79
|
|
|
77
80
|
InputTemplate.args = {
|
|
78
81
|
type: 'text',
|
|
82
|
+
isFocusDefault: false,
|
|
79
83
|
isOnlyNumber: false,
|
|
80
84
|
isOnlyString: false,
|
|
81
85
|
isPriceInput: false,
|
|
@@ -4,38 +4,39 @@ import InputMask from 'react-input-mask';
|
|
|
4
4
|
import Calendar from '../../UI/Calendar/Calendar';
|
|
5
5
|
import { useClickOutside } from '../../../Functions/useClickOutside';
|
|
6
6
|
|
|
7
|
-
const InputCalendar = ({
|
|
8
|
-
const [date, setDate] = useState(data);
|
|
9
|
-
const [inputValue, setInputValue] = useState(date);
|
|
7
|
+
const InputCalendar = ({ value, minDate, maxDate, onChange, className = '', placeholder = 'mm/dd/yyyy', mask = '99/99/9999' }) => {
|
|
10
8
|
const [isOpened, setIsOpened] = useState(false);
|
|
11
9
|
const calendarRef = useRef(null);
|
|
12
10
|
|
|
13
11
|
useClickOutside(calendarRef, () => setIsOpened(false));
|
|
14
12
|
|
|
15
|
-
const changeInputValue =
|
|
16
|
-
if (
|
|
17
|
-
setDate(moment(value).format('L'));
|
|
18
|
-
setInputValue(moment(value).format('L'));
|
|
19
|
-
} else {
|
|
20
|
-
setInputValue(value);
|
|
21
|
-
}
|
|
13
|
+
const changeInputValue = val => {
|
|
14
|
+
if (onChange) onChange(val);
|
|
22
15
|
};
|
|
23
16
|
|
|
24
|
-
const changeCalendarDay =
|
|
25
|
-
|
|
26
|
-
setInputValue(value);
|
|
17
|
+
const changeCalendarDay = val => {
|
|
18
|
+
if (onChange) onChange(val);
|
|
27
19
|
};
|
|
28
20
|
|
|
21
|
+
const getCalendarValue = (value) => {
|
|
22
|
+
const date = moment(value).format('L');
|
|
23
|
+
|
|
24
|
+
if(date !== "Invalid date") return date;
|
|
25
|
+
|
|
26
|
+
return moment(new Date()).format('L');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
29
|
return (
|
|
30
|
-
<div className=
|
|
30
|
+
<div className={`input__wrap calendar-container ${className}`} ref={calendarRef}>
|
|
31
31
|
<InputMask
|
|
32
|
-
mask=
|
|
33
|
-
|
|
32
|
+
mask={mask}
|
|
33
|
+
placeholder={placeholder}
|
|
34
|
+
value={value}
|
|
34
35
|
onChange={e => changeInputValue(e.target.value)}
|
|
35
36
|
className="calendar-dropdown"
|
|
36
37
|
onFocus={() => setIsOpened(!isOpened)}
|
|
37
38
|
/>
|
|
38
|
-
{isOpened ? <Calendar date={
|
|
39
|
+
{isOpened ? <Calendar date={getCalendarValue(value)} setDate={newDate => changeCalendarDay(newDate)} params={{ minDate, maxDate }} /> : null}
|
|
39
40
|
</div>
|
|
40
41
|
);
|
|
41
42
|
};
|
|
@@ -1,27 +1,30 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
import { ref } from 'yup';
|
|
1
|
+
import React, { useState } from 'react';
|
|
3
2
|
import InputCalendar from './InputCalendar';
|
|
4
3
|
|
|
5
4
|
global.lng = 'en';
|
|
6
5
|
|
|
6
|
+
|
|
7
7
|
export default {
|
|
8
|
-
title: 'Form Elements/
|
|
8
|
+
title: 'Form Elements/Input Calendar',
|
|
9
9
|
component: InputCalendar,
|
|
10
|
+
argTypes: {
|
|
11
|
+
value: {
|
|
12
|
+
description: 'string (mm.dd.yyyy)'
|
|
13
|
+
},
|
|
14
|
+
}
|
|
10
15
|
};
|
|
11
16
|
|
|
12
|
-
const Template =
|
|
13
|
-
const
|
|
14
|
-
minDate: args?.minDate,
|
|
15
|
-
maxDate: args?.maxDate,
|
|
16
|
-
};
|
|
17
|
+
const Template = args => {
|
|
18
|
+
const [date, setDate] = useState('');
|
|
17
19
|
|
|
18
|
-
return <InputCalendar
|
|
20
|
+
return <InputCalendar {...args} value={date} onChange={val => setDate(val)} />;
|
|
19
21
|
};
|
|
20
22
|
|
|
21
|
-
export const
|
|
23
|
+
export const CalendarTemplate = Template.bind({});
|
|
24
|
+
|
|
25
|
+
CalendarTemplate.args = {
|
|
26
|
+
value: '',
|
|
27
|
+
minDate: '10/14/2020',
|
|
28
|
+
maxDate: '10/14/2022',
|
|
22
29
|
|
|
23
|
-
Calendar.args = {
|
|
24
|
-
date: '10/14/2021',
|
|
25
|
-
minDate: '10/11/2021',
|
|
26
|
-
maxDate: '10/25/2021',
|
|
27
30
|
};
|
|
@@ -24,6 +24,8 @@ const InputDateRange = props => {
|
|
|
24
24
|
hideArrows = false,
|
|
25
25
|
isOptionsRight,
|
|
26
26
|
isUseAbs,
|
|
27
|
+
minDate = null,
|
|
28
|
+
maxDate = null,
|
|
27
29
|
} = props;
|
|
28
30
|
|
|
29
31
|
const actualValues = getActualDateRange(value);
|
|
@@ -35,6 +37,7 @@ const InputDateRange = props => {
|
|
|
35
37
|
const internalContainerRef = useRef(null);
|
|
36
38
|
|
|
37
39
|
const handleChange = input => {
|
|
40
|
+
|
|
38
41
|
const newValue = getActualDateRange(input);
|
|
39
42
|
const formatedValue = {
|
|
40
43
|
intervalKey: newValue.intervalKey,
|
|
@@ -202,6 +205,8 @@ const InputDateRange = props => {
|
|
|
202
205
|
setIsCompare={setIsCompare}
|
|
203
206
|
toggleOff={toggleOff}
|
|
204
207
|
onChange={handleChange}
|
|
208
|
+
minDate={minDate ? moment(minDate) : null}
|
|
209
|
+
maxDate={maxDate ? moment(maxDate) : null}
|
|
205
210
|
/>
|
|
206
211
|
)}
|
|
207
212
|
</div>
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
@import "../../node_modules/anme/scss/anme-mixins-media";
|
|
2
|
-
|
|
3
1
|
:root {
|
|
4
2
|
--input-height: 28px;
|
|
5
3
|
--label-line-height: 16px;
|
|
@@ -601,13 +599,13 @@
|
|
|
601
599
|
}
|
|
602
600
|
}
|
|
603
601
|
|
|
604
|
-
@
|
|
602
|
+
@media screen and (max-width: 992px) {
|
|
605
603
|
.opened-part__intervals-list {
|
|
606
604
|
display: none;
|
|
607
605
|
}
|
|
608
606
|
}
|
|
609
607
|
|
|
610
|
-
@
|
|
608
|
+
@media screen and (max-width: 745px) {
|
|
611
609
|
.date-picker__inputs-block {
|
|
612
610
|
flex-flow: wrap;
|
|
613
611
|
}
|