@true-engineering/true-react-common-ui-kit 1.0.1 → 1.1.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.
- package/LICENSE +1 -1
- package/dist/components/Modal/Modal.d.ts +1 -1
- package/dist/components/MoreMenu/MoreMenu.d.ts +2 -2
- package/dist/components/MoreMenu/MoreMenu.styles.d.ts +1 -0
- package/dist/components/Select/Select.d.ts +8 -7
- package/dist/components/Select/SelectList/SelectList.d.ts +3 -3
- package/dist/components/Select/helpers.d.ts +2 -2
- package/dist/true-react-common-ui-kit.js +315 -224
- package/dist/true-react-common-ui-kit.js.map +1 -1
- package/dist/true-react-common-ui-kit.umd.cjs +318 -227
- package/dist/true-react-common-ui-kit.umd.cjs.map +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/List/List.tsx +9 -2
- package/src/components/Modal/Modal.tsx +1 -1
- package/src/components/MoreMenu/MoreMenu.styles.ts +2 -0
- package/src/components/MoreMenu/MoreMenu.tsx +35 -24
- package/src/components/Select/Select.tsx +21 -13
- package/src/components/Select/SelectList/SelectList.tsx +8 -6
- package/src/components/Select/helpers.ts +9 -6
- package/src/components/SmartInput/SmartInput.tsx +130 -127
- package/src/types.ts +1 -1
package/dist/types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Styles } from 'react-jss';
|
|
|
2
2
|
import { Modifier, Placement } from 'react-overlays/usePopper';
|
|
3
3
|
import { ICommonIcon, IComplexIcon, IPreloaderSvgType, ISvgIcon } from './components';
|
|
4
4
|
export interface IDataAttributes {
|
|
5
|
-
[key: string]:
|
|
5
|
+
[key: string]: unknown;
|
|
6
6
|
}
|
|
7
7
|
export interface ICommonProps {
|
|
8
8
|
data?: IDataAttributes;
|
package/package.json
CHANGED
|
@@ -2,7 +2,12 @@ import { FC, Fragment, ReactElement, ReactNode } from 'react';
|
|
|
2
2
|
import clsx from 'clsx';
|
|
3
3
|
import { useTheme } from '../../hooks';
|
|
4
4
|
import { ICommonProps } from '../../types';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
isNotEmpty,
|
|
7
|
+
getTestId,
|
|
8
|
+
addDataTestId,
|
|
9
|
+
addDataAttributes,
|
|
10
|
+
} from '../../helpers';
|
|
6
11
|
import { Icon, IIconType } from '../Icon';
|
|
7
12
|
|
|
8
13
|
import { ListStyles, styles } from './List.styles';
|
|
@@ -53,7 +58,9 @@ export const List: FC<IListProps> = ({
|
|
|
53
58
|
[classes.disabledItem]: item.disabled,
|
|
54
59
|
[classes.withIconGap]: item.withIconGap,
|
|
55
60
|
})}
|
|
56
|
-
{...addDataTestId(testId, `item-${idx}`)}
|
|
61
|
+
{...addDataTestId(item.testId ?? getTestId(testId, `item-${idx}`))}
|
|
62
|
+
{...(item.disabled &&
|
|
63
|
+
addDataAttributes({ disabled: item.disabled }))}
|
|
57
64
|
onClick={item.disabled ? undefined : () => handleItemClick(item)}
|
|
58
65
|
>
|
|
59
66
|
{isNotEmpty(item.icon) && (
|
|
@@ -26,7 +26,7 @@ export type IModalPosition = 'center' | 'left' | 'right' | 'static';
|
|
|
26
26
|
|
|
27
27
|
export interface IModalProps extends ICommonProps {
|
|
28
28
|
tweakStyles?: ModalStyles;
|
|
29
|
-
title?:
|
|
29
|
+
title?: ReactNode;
|
|
30
30
|
size?: 'l' | 'm' | 's';
|
|
31
31
|
isFooterSticky?: boolean;
|
|
32
32
|
buttons?: ReactNode[];
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import { FC, MouseEvent, useRef, useState } from 'react';
|
|
1
2
|
import clsx from 'clsx';
|
|
2
|
-
import
|
|
3
|
-
|
|
3
|
+
import {
|
|
4
|
+
useTheme,
|
|
5
|
+
useTweakStyles,
|
|
6
|
+
useOnClickOutsideWithRef,
|
|
7
|
+
} from '../../hooks';
|
|
4
8
|
import { ICommonProps } from '../../types';
|
|
5
|
-
import { addDataAttributes } from '../../helpers';
|
|
9
|
+
import { addDataAttributes, addDataTestId, getTestId } from '../../helpers';
|
|
6
10
|
import { IListItem, List } from '../List';
|
|
7
11
|
import { Icon } from '../Icon';
|
|
8
12
|
|
|
@@ -12,66 +16,72 @@ export interface IMoreMenuProps extends ICommonProps {
|
|
|
12
16
|
tweakStyles?: MoreMenuStyles;
|
|
13
17
|
items: IListItem[];
|
|
14
18
|
isDisabled?: boolean;
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
/**
|
|
20
|
+
* @default true
|
|
21
|
+
*/
|
|
17
22
|
hasDefaultStateBackground?: boolean;
|
|
18
23
|
testId?: string;
|
|
24
|
+
onMenuOpen?(): void;
|
|
25
|
+
onMenuClose?(): void;
|
|
19
26
|
}
|
|
20
27
|
|
|
21
28
|
export const MoreMenu: FC<IMoreMenuProps> = ({
|
|
22
29
|
items,
|
|
23
30
|
isDisabled,
|
|
31
|
+
hasDefaultStateBackground = true,
|
|
24
32
|
data,
|
|
33
|
+
testId,
|
|
25
34
|
tweakStyles,
|
|
26
35
|
onMenuOpen,
|
|
27
36
|
onMenuClose,
|
|
28
|
-
hasDefaultStateBackground = true,
|
|
29
|
-
testId,
|
|
30
37
|
}) => {
|
|
31
|
-
const { classes } = useTheme(
|
|
38
|
+
const { classes, componentStyles } = useTheme(
|
|
39
|
+
'MoreMenu',
|
|
40
|
+
styles,
|
|
41
|
+
tweakStyles,
|
|
42
|
+
);
|
|
43
|
+
const tweakListStyles = useTweakStyles(
|
|
44
|
+
componentStyles,
|
|
45
|
+
tweakStyles,
|
|
46
|
+
'tweakList',
|
|
47
|
+
);
|
|
32
48
|
|
|
33
49
|
const [isMenuShown, setIsMenuShown] = useState(false);
|
|
34
50
|
const list = useRef<HTMLDivElement>(null);
|
|
35
51
|
const button = useRef<HTMLButtonElement>(null);
|
|
36
52
|
|
|
37
|
-
const
|
|
53
|
+
const isButtonDisabled = isDisabled || items.length === 0;
|
|
54
|
+
|
|
55
|
+
const toggleMenu = (event: MouseEvent) => {
|
|
38
56
|
const isShown = !isMenuShown;
|
|
39
57
|
event.stopPropagation();
|
|
40
58
|
setIsMenuShown(isShown);
|
|
41
59
|
if (isShown) {
|
|
42
|
-
|
|
43
|
-
onMenuOpen();
|
|
44
|
-
}
|
|
60
|
+
onMenuOpen?.();
|
|
45
61
|
} else {
|
|
46
|
-
|
|
47
|
-
onMenuClose();
|
|
48
|
-
}
|
|
62
|
+
onMenuClose?.();
|
|
49
63
|
}
|
|
50
64
|
};
|
|
51
65
|
|
|
52
66
|
const handleCloseMenu = () => {
|
|
53
67
|
setIsMenuShown(false);
|
|
54
|
-
|
|
55
|
-
onMenuClose();
|
|
56
|
-
}
|
|
68
|
+
onMenuClose?.();
|
|
57
69
|
};
|
|
58
70
|
|
|
59
71
|
useOnClickOutsideWithRef(list, handleCloseMenu, button);
|
|
60
72
|
|
|
61
|
-
const isButtonDisabled = isDisabled || items.length === 0;
|
|
62
|
-
|
|
63
73
|
return (
|
|
64
74
|
<div className={classes.root}>
|
|
65
75
|
<button
|
|
76
|
+
ref={button}
|
|
66
77
|
className={clsx(classes.button, {
|
|
67
78
|
[classes.hasCircle]: hasDefaultStateBackground,
|
|
68
79
|
[classes.disabled]: isButtonDisabled,
|
|
69
80
|
[classes.active]: isMenuShown,
|
|
70
81
|
})}
|
|
71
|
-
|
|
72
|
-
ref={button}
|
|
73
|
-
data-testid={testId}
|
|
82
|
+
{...addDataTestId(testId)}
|
|
74
83
|
{...addDataAttributes(data)}
|
|
84
|
+
onClick={!isButtonDisabled ? toggleMenu : undefined}
|
|
75
85
|
>
|
|
76
86
|
<div className={classes.icon}>
|
|
77
87
|
<Icon type="menu" />
|
|
@@ -81,8 +91,9 @@ export const MoreMenu: FC<IMoreMenuProps> = ({
|
|
|
81
91
|
<div className={classes.menu} ref={list}>
|
|
82
92
|
<List
|
|
83
93
|
items={items}
|
|
94
|
+
testId={getTestId(testId, 'list')}
|
|
95
|
+
tweakStyles={tweakListStyles}
|
|
84
96
|
onClick={handleCloseMenu}
|
|
85
|
-
testId={testId !== undefined ? `${testId}-list` : undefined}
|
|
86
97
|
/>
|
|
87
98
|
</div>
|
|
88
99
|
)}
|
|
@@ -22,14 +22,15 @@ import {
|
|
|
22
22
|
useDropdown,
|
|
23
23
|
} from '../../hooks';
|
|
24
24
|
import { IDropdownWithPopperOptions } from '../../types';
|
|
25
|
-
|
|
26
|
-
import { SelectStyles, styles } from './Select.styles';
|
|
25
|
+
import { isNotEmpty } from '../../helpers';
|
|
27
26
|
import {
|
|
28
27
|
defaultConvertFunction,
|
|
29
28
|
defaultCompareFunction,
|
|
30
29
|
getActiveValueIndex,
|
|
31
30
|
} from './helpers';
|
|
32
31
|
|
|
32
|
+
import { SelectStyles, styles } from './Select.styles';
|
|
33
|
+
|
|
33
34
|
export interface ISelectProps<Value>
|
|
34
35
|
extends Omit<IInputProps, 'value' | 'onChange' | 'type'> {
|
|
35
36
|
tweakStyles?: SelectStyles;
|
|
@@ -46,19 +47,17 @@ export interface ISelectProps<Value>
|
|
|
46
47
|
|
|
47
48
|
optionsFilter?: (options: Value[], query: string) => Value[];
|
|
48
49
|
options: Value[];
|
|
49
|
-
value
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
v2: Value | undefined,
|
|
54
|
-
) => boolean;
|
|
50
|
+
value: Value | undefined;
|
|
51
|
+
shouldScrollToList?: boolean;
|
|
52
|
+
onChange(value: Value | undefined): void; // подумать как возвращать индекс
|
|
53
|
+
compareValuesOnChange?(v1: Value | undefined, v2: Value | undefined): boolean;
|
|
55
54
|
// возможно делать какую-то индексацию опций
|
|
56
55
|
|
|
57
56
|
// Для избежания проблем юзайте useCallback на эти функции
|
|
58
57
|
// или выносите их из компонента (чтобы не было сайдэфектов от перерендеринга их)
|
|
59
|
-
convertValueToString
|
|
60
|
-
convertValueToReactNode
|
|
61
|
-
convertValueToId
|
|
58
|
+
convertValueToString?(value: Value): string | undefined;
|
|
59
|
+
convertValueToReactNode?(value: Value): ReactNode;
|
|
60
|
+
convertValueToId?(value: Value): string | undefined;
|
|
62
61
|
}
|
|
63
62
|
|
|
64
63
|
export function Select<Value>({
|
|
@@ -85,6 +84,7 @@ export function Select<Value>({
|
|
|
85
84
|
dropdownOptions,
|
|
86
85
|
minSymbolsCountToOpenList = 0,
|
|
87
86
|
dropdownIcon = 'chevron-down',
|
|
87
|
+
shouldScrollToList = true,
|
|
88
88
|
...inputProps
|
|
89
89
|
}: ISelectProps<Value>): JSX.Element {
|
|
90
90
|
const { classes, componentStyles } = useTheme('Select', styles, tweakStyles);
|
|
@@ -104,6 +104,10 @@ export function Select<Value>({
|
|
|
104
104
|
const list = useRef<HTMLDivElement>(null);
|
|
105
105
|
const input = useRef<HTMLInputElement>(null); // TODO ref снаружи?
|
|
106
106
|
|
|
107
|
+
const stringValue = isNotEmpty(value)
|
|
108
|
+
? convertValueToString(value)
|
|
109
|
+
: undefined;
|
|
110
|
+
|
|
107
111
|
const filteredOptions = useMemo(() => {
|
|
108
112
|
if (optionsMode !== 'search') {
|
|
109
113
|
return options;
|
|
@@ -369,7 +373,7 @@ export function Select<Value>({
|
|
|
369
373
|
ref={inputWrapper}
|
|
370
374
|
>
|
|
371
375
|
<Input
|
|
372
|
-
value={searchValue !== '' ? searchValue :
|
|
376
|
+
value={searchValue !== '' ? searchValue : stringValue}
|
|
373
377
|
onChange={handleInputChange}
|
|
374
378
|
isActive={isListOpen}
|
|
375
379
|
isReadonly={optionsMode === 'normal'}
|
|
@@ -428,7 +432,11 @@ export function Select<Value>({
|
|
|
428
432
|
tweakStyles={tweakStyles?.tweakSelectList as Styles}
|
|
429
433
|
testId={testId !== undefined ? `${testId}-list` : undefined}
|
|
430
434
|
// скролл не работает с включеным поппером
|
|
431
|
-
shouldScrollToList={
|
|
435
|
+
shouldScrollToList={
|
|
436
|
+
shouldScrollToList &&
|
|
437
|
+
!shouldUsePopper &&
|
|
438
|
+
!shouldHideOnScroll
|
|
439
|
+
}
|
|
432
440
|
/>
|
|
433
441
|
)}
|
|
434
442
|
</div>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React, { ReactNode, useMemo } from 'react';
|
|
2
|
-
import { ScrollIntoViewIfNeeded } from '../../ScrollIntoViewIfNeeded';
|
|
3
2
|
import clsx from 'clsx';
|
|
4
|
-
|
|
3
|
+
import { ScrollIntoViewIfNeeded } from '../../ScrollIntoViewIfNeeded';
|
|
5
4
|
import { useTheme } from '../../../hooks';
|
|
6
5
|
import { ICommonProps } from '../../../types';
|
|
6
|
+
import { isNotEmpty } from '../../../helpers';
|
|
7
7
|
|
|
8
8
|
import { SelectListStyles, styles } from './SelectList.styles';
|
|
9
9
|
|
|
@@ -19,9 +19,9 @@ export interface ISelectListProps<Value> extends ICommonProps {
|
|
|
19
19
|
onOptionClick: (index: number) => void;
|
|
20
20
|
testId?: string;
|
|
21
21
|
shouldScrollToList?: boolean;
|
|
22
|
-
convertValueToString: (value
|
|
23
|
-
convertValueToReactNode?: (value
|
|
24
|
-
convertValueToId?: (value
|
|
22
|
+
convertValueToString: (value: Value) => string | undefined;
|
|
23
|
+
convertValueToReactNode?: (value: Value) => ReactNode;
|
|
24
|
+
convertValueToId?: (value: Value) => string | undefined;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export function isOptionDisabled<Value>(option: Value): boolean {
|
|
@@ -51,7 +51,9 @@ export function SelectList<Value>({
|
|
|
51
51
|
shouldScrollToList = true,
|
|
52
52
|
}: ISelectListProps<Value>): JSX.Element {
|
|
53
53
|
const { classes } = useTheme('SelectList', styles, tweakStyles);
|
|
54
|
-
const activeValueId =
|
|
54
|
+
const activeValueId = isNotEmpty(activeValue)
|
|
55
|
+
? convertValueToId(activeValue)
|
|
56
|
+
: undefined;
|
|
55
57
|
|
|
56
58
|
const convertedToStringOptions = useMemo(
|
|
57
59
|
() => options.map(convertValueToString),
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
+
import { isNotEmpty } from '../../helpers';
|
|
2
|
+
|
|
1
3
|
export const defaultConvertFunction = (v: unknown) =>
|
|
2
4
|
v === undefined ? undefined : String(v);
|
|
3
5
|
|
|
4
|
-
export const defaultCompareFunction = <Value>(
|
|
5
|
-
v1
|
|
6
|
-
v2: Value | undefined,
|
|
7
|
-
) => v1 === v2;
|
|
6
|
+
export const defaultCompareFunction = <Value>(v1: Value, v2: Value) =>
|
|
7
|
+
v1 === v2;
|
|
8
8
|
|
|
9
9
|
export const getActiveValueIndex = <Value>(
|
|
10
10
|
options: Value[],
|
|
11
11
|
value: Value | undefined,
|
|
12
|
-
convertFunc: (v
|
|
13
|
-
): number =>
|
|
12
|
+
convertFunc: (v: Value) => string | undefined,
|
|
13
|
+
): number =>
|
|
14
|
+
isNotEmpty(value)
|
|
15
|
+
? options.findIndex((o) => convertFunc(o) === convertFunc(value))
|
|
16
|
+
: -1;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {useState, useEffect, forwardRef} from 'react';
|
|
1
|
+
import React, { useState, useEffect, forwardRef } from 'react';
|
|
2
2
|
import { Input, IInputProps } from '../Input';
|
|
3
3
|
import {
|
|
4
4
|
CharactersMap,
|
|
@@ -38,140 +38,143 @@ export const SMART_INPUT_REGEX_MAP = {
|
|
|
38
38
|
benefitCert: /^[a-zA-Z0-9/]*$/i,
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
-
export const SmartInput = forwardRef<HTMLInputElement, ISmartInputProps>(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
41
|
+
export const SmartInput = forwardRef<HTMLInputElement, ISmartInputProps>(
|
|
42
|
+
(
|
|
43
|
+
{
|
|
44
|
+
onChange,
|
|
45
|
+
isUpperCase,
|
|
46
|
+
smartType = 'default',
|
|
47
|
+
regExp,
|
|
48
|
+
value = '',
|
|
49
|
+
maxLength,
|
|
50
|
+
...rest
|
|
51
|
+
},
|
|
52
|
+
ref,
|
|
53
|
+
) => {
|
|
54
|
+
const [currentValue, setCurrentValue] = useState<string>(
|
|
55
|
+
getUpperCaseIfNeeded(value),
|
|
56
|
+
);
|
|
57
|
+
const [caretPosition, setCaretPosition] = useState<number | null>(null);
|
|
58
|
+
const [input, setInput] = useState<HTMLInputElement | null>(null);
|
|
59
|
+
const regex = regExp || SMART_INPUT_REGEX_MAP[smartType];
|
|
60
|
+
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (
|
|
63
|
+
input &&
|
|
64
|
+
input.type !== 'email' &&
|
|
65
|
+
input.selectionStart !== caretPosition
|
|
66
|
+
) {
|
|
67
|
+
input.selectionStart = caretPosition;
|
|
68
|
+
input.selectionEnd = caretPosition;
|
|
69
|
+
}
|
|
70
|
+
}, [caretPosition]);
|
|
71
|
+
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
setCurrentValue(getUpperCaseIfNeeded(value));
|
|
74
|
+
}, [value]);
|
|
75
|
+
|
|
76
|
+
function getUpperCaseIfNeeded(str: string) {
|
|
77
|
+
return isUpperCase ? str.toUpperCase() : str;
|
|
65
78
|
}
|
|
66
|
-
}, [caretPosition]);
|
|
67
79
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
80
|
+
const handleChange = (
|
|
81
|
+
str: string,
|
|
82
|
+
event?: React.FormEvent<HTMLInputElement>,
|
|
83
|
+
) => {
|
|
84
|
+
const mappedValue = str
|
|
85
|
+
.split('')
|
|
86
|
+
.map((symbol) =>
|
|
87
|
+
regex.test(symbol)
|
|
88
|
+
? symbol
|
|
89
|
+
: transformCaseSensitive(
|
|
90
|
+
smartType,
|
|
91
|
+
smartType !== 'email'
|
|
92
|
+
? CharactersMap
|
|
93
|
+
: { ...CharactersMap, '"': '@' },
|
|
94
|
+
symbol,
|
|
95
|
+
),
|
|
96
|
+
)
|
|
97
|
+
.filter((symbol) => regex.test(symbol))
|
|
98
|
+
.join('');
|
|
99
|
+
const domElement = event?.currentTarget;
|
|
100
|
+
|
|
101
|
+
if (domElement) {
|
|
102
|
+
if (!input) {
|
|
103
|
+
setInput(domElement);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
setCurrentValue(getUpperCaseIfNeeded(mappedValue));
|
|
107
|
+
onChange(getUpperCaseIfNeeded(mappedValue));
|
|
108
|
+
|
|
109
|
+
if (mappedValue !== currentValue) {
|
|
110
|
+
setCaretPosition(domElement.selectionStart);
|
|
111
|
+
} else {
|
|
112
|
+
setCaretPosition(
|
|
113
|
+
domElement.selectionStart ? domElement.selectionStart - 1 : null,
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
};
|
|
71
118
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
119
|
+
const handlePaste = (event: React.ClipboardEvent<HTMLInputElement>) => {
|
|
120
|
+
const str = event.clipboardData.getData('text/plain').split('').join('');
|
|
121
|
+
const domElement = event.currentTarget;
|
|
75
122
|
|
|
76
|
-
const handleChange = (
|
|
77
|
-
str: string,
|
|
78
|
-
event?: React.FormEvent<HTMLInputElement>,
|
|
79
|
-
) => {
|
|
80
|
-
const mappedValue = str
|
|
81
|
-
.split('')
|
|
82
|
-
.map((symbol) =>
|
|
83
|
-
regex.test(symbol)
|
|
84
|
-
? symbol
|
|
85
|
-
: transformCaseSensitive(
|
|
86
|
-
smartType,
|
|
87
|
-
smartType !== 'email'
|
|
88
|
-
? CharactersMap
|
|
89
|
-
: { ...CharactersMap, '"': '@' },
|
|
90
|
-
symbol,
|
|
91
|
-
),
|
|
92
|
-
)
|
|
93
|
-
.filter((symbol) => regex.test(symbol))
|
|
94
|
-
.join('');
|
|
95
|
-
const domElement = event?.currentTarget;
|
|
96
|
-
|
|
97
|
-
if (domElement) {
|
|
98
123
|
if (!input) {
|
|
99
124
|
setInput(domElement);
|
|
100
125
|
}
|
|
101
126
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
127
|
+
event.preventDefault();
|
|
128
|
+
const selectionStart = domElement.selectionStart ?? 0;
|
|
129
|
+
const selectionEnd = domElement.selectionEnd ?? 0;
|
|
130
|
+
|
|
131
|
+
let mappedValue = str
|
|
132
|
+
.split('')
|
|
133
|
+
.map((symbol) =>
|
|
134
|
+
regex.test(symbol)
|
|
135
|
+
? symbol
|
|
136
|
+
: transformCaseSensitive(smartType, TransliterationMap, symbol),
|
|
137
|
+
)
|
|
138
|
+
.filter((letter) => regex.test(letter))
|
|
139
|
+
.join('');
|
|
140
|
+
|
|
141
|
+
const newValueLength =
|
|
142
|
+
mappedValue.length +
|
|
143
|
+
currentValue.length -
|
|
144
|
+
(selectionEnd - selectionStart);
|
|
145
|
+
|
|
146
|
+
if (
|
|
147
|
+
maxLength !== undefined &&
|
|
148
|
+
maxLength >= 0 &&
|
|
149
|
+
newValueLength > maxLength
|
|
150
|
+
) {
|
|
151
|
+
const validMappedValueLength =
|
|
152
|
+
mappedValue.length - (newValueLength - maxLength);
|
|
153
|
+
|
|
154
|
+
mappedValue = mappedValue.substring(0, validMappedValueLength);
|
|
111
155
|
}
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
const handlePaste = (event: React.ClipboardEvent<HTMLInputElement>) => {
|
|
116
|
-
const str = event.clipboardData.getData('text/plain').split('').join('');
|
|
117
|
-
const domElement = event.currentTarget;
|
|
118
|
-
|
|
119
|
-
if (!input) {
|
|
120
|
-
setInput(domElement);
|
|
121
|
-
}
|
|
122
156
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
maxLength >= 0 &&
|
|
145
|
-
newValueLength > maxLength
|
|
146
|
-
) {
|
|
147
|
-
const validMappedValueLength =
|
|
148
|
-
mappedValue.length - (newValueLength - maxLength);
|
|
149
|
-
|
|
150
|
-
mappedValue = mappedValue.substring(0, validMappedValueLength);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const newValue = getUpperCaseIfNeeded(
|
|
154
|
-
`${currentValue?.substring(
|
|
155
|
-
0,
|
|
156
|
-
selectionStart,
|
|
157
|
-
)}${mappedValue}${currentValue?.substring(
|
|
158
|
-
selectionEnd,
|
|
159
|
-
)}`,
|
|
157
|
+
const newValue = getUpperCaseIfNeeded(
|
|
158
|
+
`${currentValue?.substring(
|
|
159
|
+
0,
|
|
160
|
+
selectionStart,
|
|
161
|
+
)}${mappedValue}${currentValue?.substring(selectionEnd)}`,
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
setCaretPosition(selectionStart + mappedValue.length);
|
|
165
|
+
setCurrentValue(newValue);
|
|
166
|
+
onChange(newValue);
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
return (
|
|
170
|
+
<Input
|
|
171
|
+
{...rest}
|
|
172
|
+
ref={ref}
|
|
173
|
+
maxLength={maxLength}
|
|
174
|
+
onChange={handleChange}
|
|
175
|
+
onPaste={handlePaste}
|
|
176
|
+
value={currentValue}
|
|
177
|
+
/>
|
|
160
178
|
);
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
setCurrentValue(newValue);
|
|
164
|
-
onChange(newValue);
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
return (
|
|
168
|
-
<Input
|
|
169
|
-
{...rest}
|
|
170
|
-
ref={ref}
|
|
171
|
-
maxLength={maxLength}
|
|
172
|
-
onChange={handleChange}
|
|
173
|
-
onPaste={handlePaste}
|
|
174
|
-
value={currentValue}
|
|
175
|
-
/>
|
|
176
|
-
);
|
|
177
|
-
});
|
|
179
|
+
},
|
|
180
|
+
);
|