@true-engineering/true-react-common-ui-kit 4.0.0-alpha5 → 4.0.0-alpha6
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/README.md +53 -0
- package/dist/components/FiltersPane/types.d.ts +15 -5
- package/dist/components/Flag/customFlags/customFlags.d.ts +10 -0
- package/dist/components/Flag/customFlags/index.d.ts +1 -0
- package/dist/components/FlexibleTable/FlexibleTable.d.ts +1 -1
- package/dist/components/FlexibleTable/components/FlexibleTableRow/FlexibleTableRow.d.ts +5 -4
- package/dist/components/FlexibleTable/constants.d.ts +18 -2
- package/dist/components/FlexibleTable/types.d.ts +1 -1
- package/dist/components/SearchInput/SearchInput.d.ts +2 -2
- package/dist/components/SearchInput/SearchInput.stories.d.ts +3 -2
- package/dist/components/Select/Select.d.ts +5 -3
- package/dist/components/Tooltip/Tooltip.d.ts +1 -1
- package/dist/components/Tooltip/Tooltip.styles.d.ts +1 -1
- package/dist/true-react-common-ui-kit.js +112 -78
- package/dist/true-react-common-ui-kit.js.map +1 -1
- package/dist/true-react-common-ui-kit.umd.cjs +111 -77
- package/dist/true-react-common-ui-kit.umd.cjs.map +1 -1
- package/package.json +1 -1
- package/src/components/FiltersPane/components/FilterValueView/FilterValueView.tsx +19 -17
- package/src/components/FiltersPane/types.ts +23 -5
- package/src/components/Flag/Flag.stories.tsx +2 -1
- package/src/components/Flag/Flag.styles.ts +4 -0
- package/src/components/Flag/Flag.tsx +23 -9
- package/src/components/Flag/customFlags/AB.svg +1 -0
- package/src/components/Flag/customFlags/OS.svg +1 -0
- package/src/components/Flag/customFlags/augment.d.ts +1 -0
- package/src/components/Flag/customFlags/customFlags.ts +13 -0
- package/src/components/Flag/customFlags/index.ts +1 -0
- package/src/components/FlexibleTable/FlexibleTable.tsx +1 -0
- package/src/components/FlexibleTable/components/FlexibleTableRow/FlexibleTableRow.tsx +6 -3
- package/src/components/FlexibleTable/constants.ts +6 -3
- package/src/components/FlexibleTable/types.ts +1 -5
- package/src/components/PhoneInput/PhoneInput.stories.tsx +2 -1
- package/src/components/PhoneInput/PhoneInput.tsx +5 -2
- package/src/components/SearchInput/SearchInput.tsx +23 -28
- package/src/components/Select/Select.tsx +11 -2
- package/src/components/Tooltip/Tooltip.styles.ts +2 -0
- package/src/components/Tooltip/Tooltip.tsx +1 -1
- package/src/constants/phone-info.ts +20 -33
- package/src/helpers/phone.ts +19 -15
package/package.json
CHANGED
|
@@ -29,7 +29,7 @@ export function FilterValueView<Values, Key extends keyof Values>({
|
|
|
29
29
|
return <></>;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
if (filter.getSelectedValueView
|
|
32
|
+
if (isNotEmpty(filter.getSelectedValueView)) {
|
|
33
33
|
return <span className={classes.text}>{filter.getSelectedValueView(value)}</span>;
|
|
34
34
|
}
|
|
35
35
|
|
|
@@ -94,7 +94,7 @@ export function FilterValueView<Values, Key extends keyof Values>({
|
|
|
94
94
|
const intervalValueFrom = intervalValue[0];
|
|
95
95
|
const intervalValueTo = intervalValue[1];
|
|
96
96
|
|
|
97
|
-
const intervals = [];
|
|
97
|
+
const intervals: string[] = [];
|
|
98
98
|
if (intervalValueFrom !== undefined) {
|
|
99
99
|
intervals.push(`${translates.from.toLowerCase()} ${String(intervalValueFrom)}`);
|
|
100
100
|
}
|
|
@@ -105,19 +105,6 @@ export function FilterValueView<Values, Key extends keyof Values>({
|
|
|
105
105
|
return <span className={classes.text}>{intervals.join(' ')}</span>;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
if (isMultiple) {
|
|
109
|
-
return (
|
|
110
|
-
<>
|
|
111
|
-
{Array.isArray(value) && value.length > 0 && (
|
|
112
|
-
<>
|
|
113
|
-
<span className={classes.text}>{displayValue(value[0])}</span>
|
|
114
|
-
<span className={classes.count}>{value.length > 1 && ` (+${value.length - 1})`}</span>
|
|
115
|
-
</>
|
|
116
|
-
)}
|
|
117
|
-
</>
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
108
|
if (isDate) {
|
|
122
109
|
const { from, to, periodType, label } = value as unknown as IPeriod;
|
|
123
110
|
const hasFrom = from !== undefined && from !== null;
|
|
@@ -127,7 +114,7 @@ export function FilterValueView<Values, Key extends keyof Values>({
|
|
|
127
114
|
return <span className={classes.text}>{displayValue(label)}</span>;
|
|
128
115
|
}
|
|
129
116
|
|
|
130
|
-
const range = [];
|
|
117
|
+
const range: string[] = [];
|
|
131
118
|
if (hasFrom) {
|
|
132
119
|
if (!hasTo) {
|
|
133
120
|
range.push(translates.from.toLowerCase());
|
|
@@ -146,12 +133,27 @@ export function FilterValueView<Values, Key extends keyof Values>({
|
|
|
146
133
|
return <span className={classes.text}>{range.join(' ')}</span>;
|
|
147
134
|
}
|
|
148
135
|
|
|
136
|
+
if (isMultiple) {
|
|
137
|
+
const convertValue = filter.getSelectedValue ?? displayValue;
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<>
|
|
141
|
+
{Array.isArray(value) && value.length > 0 && (
|
|
142
|
+
<>
|
|
143
|
+
<span className={classes.text}>{convertValue(value[0])}</span>
|
|
144
|
+
<span className={classes.count}>{value.length > 1 && ` (+${value.length - 1})`}</span>
|
|
145
|
+
</>
|
|
146
|
+
)}
|
|
147
|
+
</>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
149
151
|
if (isRange && Array.isArray(value)) {
|
|
150
152
|
const rangeValue = value as unknown as number[];
|
|
151
153
|
const rangeValueFrom = rangeValue[0];
|
|
152
154
|
const rangeValueTo = rangeValue[1];
|
|
153
155
|
|
|
154
|
-
const range = [];
|
|
156
|
+
const range: string[] = [];
|
|
155
157
|
if (rangeValueFrom !== undefined) {
|
|
156
158
|
range.push(`${translates.from.toLowerCase()} ${String(rangeValueFrom)}`);
|
|
157
159
|
}
|
|
@@ -84,22 +84,40 @@ export type IDateRangeConfigItem<Value> = IConfigItemBasicBase<Value> & {
|
|
|
84
84
|
dateFormat?: string;
|
|
85
85
|
} & Omit<IFilterWithPeriodProps, 'value' | 'onChange' | 'setIsOpen'>;
|
|
86
86
|
|
|
87
|
-
export
|
|
87
|
+
export interface ICustomComponentProps<Value> {
|
|
88
88
|
value?: Value;
|
|
89
89
|
onChange: (v?: Value) => void;
|
|
90
90
|
onClose?: () => void;
|
|
91
91
|
filter: ICustomConfigItem<Value>;
|
|
92
92
|
localeKey?: IFilterLocaleKey;
|
|
93
93
|
locale?: IPartialFilterLocale;
|
|
94
|
-
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export type CustomComponent<Value> = FC<ICustomComponentProps<Value>>;
|
|
97
|
+
|
|
98
|
+
export type ICustomValue<V> = V extends Array<infer T> ? T : never;
|
|
99
|
+
|
|
100
|
+
export interface ICustomRangeConfigItem<Value> extends IConfigItemBasicBase<Value> {
|
|
101
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
102
|
+
[key: string & {}]: any;
|
|
103
|
+
type: 'custom';
|
|
104
|
+
component: CustomComponent<Value>;
|
|
105
|
+
valueViewType?: 'range';
|
|
106
|
+
}
|
|
95
107
|
|
|
96
|
-
export interface
|
|
97
|
-
|
|
108
|
+
export interface ICustomMultipleConfigItem<Value> extends IConfigItemBasicBase<Value> {
|
|
109
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
110
|
+
[key: string & {}]: any;
|
|
98
111
|
type: 'custom';
|
|
99
112
|
component: CustomComponent<Value>;
|
|
100
|
-
valueViewType?: '
|
|
113
|
+
valueViewType?: 'multiple';
|
|
114
|
+
getSelectedValue?: (v: ICustomValue<Value>) => ReactNode;
|
|
101
115
|
}
|
|
102
116
|
|
|
117
|
+
export type ICustomConfigItem<Value> =
|
|
118
|
+
| ICustomRangeConfigItem<Value>
|
|
119
|
+
| ICustomMultipleConfigItem<Value>;
|
|
120
|
+
|
|
103
121
|
export type ConfigItem<Value> =
|
|
104
122
|
| ISelectConfigItem<Value>
|
|
105
123
|
| IMultiSelectConfigItem<Value>
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { countries } from 'country-flag-icons';
|
|
2
2
|
import { ComponentStory } from '@storybook/react';
|
|
3
3
|
import { Flag } from './Flag';
|
|
4
|
+
import { customFlags } from './customFlags';
|
|
4
5
|
|
|
5
6
|
export default {
|
|
6
7
|
title: 'Data Display/Flag',
|
|
7
8
|
component: Flag,
|
|
8
9
|
argTypes: {
|
|
9
|
-
countryCode: { control: 'select', options: countries },
|
|
10
|
+
countryCode: { control: 'select', options: [...countries, ...Object.keys(customFlags)] },
|
|
10
11
|
},
|
|
11
12
|
};
|
|
12
13
|
|
|
@@ -2,6 +2,10 @@ import { colors, ITweakStyles, createThemedStyles } from '../../theme';
|
|
|
2
2
|
|
|
3
3
|
export const useStyles = createThemedStyles('Flag', {
|
|
4
4
|
root: {
|
|
5
|
+
display: 'flex',
|
|
6
|
+
width: '100%',
|
|
7
|
+
height: '100%',
|
|
8
|
+
boxSizing: 'border-box',
|
|
5
9
|
// приходится хардкодить в компоненте, тк либа Flags выдает флаги с 2-3 пиксельным отступом снизу
|
|
6
10
|
// если будет нужно, то можно вынести border на уровень пропсов
|
|
7
11
|
border: [1, 'solid', colors.BORDER_MAIN],
|
|
@@ -3,6 +3,7 @@ import { hasFlag } from 'country-flag-icons';
|
|
|
3
3
|
import Flags from 'country-flag-icons/react/3x2';
|
|
4
4
|
import { ICommonProps } from '../../types';
|
|
5
5
|
import { Icon } from '../Icon';
|
|
6
|
+
import { customFlags } from './customFlags';
|
|
6
7
|
import { useStyles, IFlagStyles } from './Flag.styles';
|
|
7
8
|
|
|
8
9
|
export interface IFlagProps extends Pick<ICommonProps<IFlagStyles>, 'tweakStyles'> {
|
|
@@ -12,15 +13,28 @@ export interface IFlagProps extends Pick<ICommonProps<IFlagStyles>, 'tweakStyles
|
|
|
12
13
|
|
|
13
14
|
export const Flag: FC<IFlagProps> = ({ countryCode = '', tweakStyles }) => {
|
|
14
15
|
const classes = useStyles({ theme: tweakStyles });
|
|
15
|
-
const
|
|
16
|
+
const countryFlagKey = countryCode.toUpperCase();
|
|
16
17
|
|
|
17
|
-
const
|
|
18
|
-
? Flags[CC as keyof typeof Flags]
|
|
19
|
-
: () => (
|
|
20
|
-
<div className={classes.noFlag}>
|
|
21
|
-
<Icon type="minus" />
|
|
22
|
-
</div>
|
|
23
|
-
);
|
|
18
|
+
const hasFlagInLibrary = hasFlag(countryFlagKey);
|
|
24
19
|
|
|
25
|
-
|
|
20
|
+
if (hasFlagInLibrary) {
|
|
21
|
+
const FlagComponent = Flags[countryFlagKey as keyof typeof Flags];
|
|
22
|
+
return (
|
|
23
|
+
<div className={classes.root}>
|
|
24
|
+
<FlagComponent />
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const CustomFlag = customFlags[countryFlagKey as keyof typeof customFlags];
|
|
30
|
+
|
|
31
|
+
if (CustomFlag !== undefined) {
|
|
32
|
+
return <div className={classes.root} dangerouslySetInnerHTML={{ __html: CustomFlag }} />;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div className={classes.noFlag}>
|
|
37
|
+
<Icon type="minus" />
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
26
40
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 341.3"><path fill="#FFF" d="M0 0h512v341.3H0z"/><g fill="#6DA544"><path d="M0 0h512v48.8H0zM0 97.5h512v48.8H0zM0 195h512v48.8H0zM0 292.6h512v48.8H0z"/></g><path fill="#D80027" d="M0 0h256v146.3H0z"/><path fill="#FFF" d="m116.9 114.4-7.5-14.8V69.9L128 59l18.6 10.9v22.3l7.4-7.4 4.2 3-4.2 11.8-14.9 14.8z"/><circle fill="#FFF" cx="82" cy="82.8" r="5.4"/><circle fill="#FFF" cx="90.8" cy="61.7" r="5.4"/><circle fill="#FFF" cx="106.6" cy="46.2" r="5.4"/><circle fill="#FFF" cx="128" cy="40.8" r="5.4"/><circle fill="#FFF" cx="149.4" cy="46.2" r="5.4"/><circle fill="#FFF" cx="165.2" cy="61.7" r="5.4"/><circle fill="#FFF" cx="174" cy="82.8" r="5.4"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 450 300"><path fill="#FFF" d="M0 0h450v300H0z"/><path fill="red" d="M0 100h450v200H0z"/><path fill="#FFDF00" d="M0 200h450v100H0z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
declare module '*.svg?raw';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './customFlags';
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { ReactNode, useState, memo, MouseEvent } from 'react';
|
|
1
|
+
import { ReactNode, useState, memo, MouseEvent, RefCallback } from 'react';
|
|
2
2
|
import clsx from 'clsx';
|
|
3
3
|
import { applyAction, isEmpty, isNotEmpty } from '@true-engineering/true-react-platform-helpers';
|
|
4
4
|
import { addDataAttributes } from '../../../../helpers';
|
|
5
5
|
import { useTweakStyles } from '../../../../hooks';
|
|
6
|
-
import {
|
|
6
|
+
import { IDataAttributes, ITweakStylesProps } from '../../../../types';
|
|
7
7
|
import { TableRenders } from '../../constants';
|
|
8
8
|
import {
|
|
9
9
|
ITableRow,
|
|
@@ -19,7 +19,7 @@ export interface IFlexibleTableRowProps<
|
|
|
19
19
|
Row extends ITableRow,
|
|
20
20
|
HeaderContent extends IHeaderContent<Row>,
|
|
21
21
|
UniqueField extends keyof Row,
|
|
22
|
-
> extends
|
|
22
|
+
> extends ITweakStylesProps<IFlexibleTableRowStyles> {
|
|
23
23
|
item: Row;
|
|
24
24
|
index: number;
|
|
25
25
|
uniqueField?: UniqueField;
|
|
@@ -38,6 +38,7 @@ export interface IFlexibleTableRowProps<
|
|
|
38
38
|
rowAttributes?: Array<keyof Row>;
|
|
39
39
|
/** @default false */
|
|
40
40
|
isExpandableRowComponentInitiallyOpen?: boolean | ((row: Row, index: number) => boolean);
|
|
41
|
+
rowRef?: RefCallback<HTMLTableRowElement>;
|
|
41
42
|
/** Возвращает React-элемент, который отрисуется под строкой при нажатии на неё */
|
|
42
43
|
expandableRowComponent?: (item: Row, isOpen: boolean, close: () => void) => ReactNode;
|
|
43
44
|
onRowHover?: (id?: Row[UniqueField]) => void;
|
|
@@ -61,6 +62,7 @@ function FlexibleTableRowInner<
|
|
|
61
62
|
isLoading = false,
|
|
62
63
|
rowAttributes,
|
|
63
64
|
isExpandableRowComponentInitiallyOpen = false,
|
|
65
|
+
rowRef,
|
|
64
66
|
tweakStyles,
|
|
65
67
|
expandableRowComponent,
|
|
66
68
|
onRowHover,
|
|
@@ -139,6 +141,7 @@ function FlexibleTableRowInner<
|
|
|
139
141
|
return (
|
|
140
142
|
<>
|
|
141
143
|
<Table.Row
|
|
144
|
+
ref={rowRef}
|
|
142
145
|
className={clsx(classes.root, {
|
|
143
146
|
[classes.active]: isActive,
|
|
144
147
|
[classes.editable]: isEditable,
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IFlexibleTableRenderElement, IFlexibleTableRenderMode } from './types';
|
|
2
2
|
|
|
3
3
|
export const DEFAULT_DATE_FORMAT = 'dd.MM.yyyy';
|
|
4
4
|
|
|
5
|
-
export const TableRenders
|
|
5
|
+
export const TableRenders = {
|
|
6
6
|
table: { Root: 'table', Head: 'thead', Body: 'tbody', Row: 'tr', Header: 'th', Cell: 'td' },
|
|
7
7
|
divs: { Root: 'div', Head: 'div', Body: 'div', Row: 'div', Header: 'div', Cell: 'div' },
|
|
8
|
-
}
|
|
8
|
+
} satisfies Record<
|
|
9
|
+
IFlexibleTableRenderMode,
|
|
10
|
+
Record<IFlexibleTableRenderElement, keyof JSX.IntrinsicElements>
|
|
11
|
+
>;
|
|
@@ -2,11 +2,7 @@ import { CSSProperties, MouseEvent, ReactNode } from 'react';
|
|
|
2
2
|
import { IRenderNode } from '../../types';
|
|
3
3
|
|
|
4
4
|
export type IFlexibleTableRenderMode = 'table' | 'divs';
|
|
5
|
-
|
|
6
|
-
export type IFlexibleTableRender = Record<
|
|
7
|
-
'Root' | 'Head' | 'Body' | 'Row' | 'Header' | 'Cell',
|
|
8
|
-
keyof JSX.IntrinsicElements
|
|
9
|
-
>;
|
|
5
|
+
export type IFlexibleTableRenderElement = 'Root' | 'Head' | 'Body' | 'Row' | 'Header' | 'Cell';
|
|
10
6
|
|
|
11
7
|
// TODO: Заменить Record<string, any> на Record<string, unknown>
|
|
12
8
|
export type ITableRow = Record<string, any>;
|
|
@@ -26,7 +26,8 @@ export default {
|
|
|
26
26
|
const Template: ComponentStory<typeof PhoneInput> = (args) => {
|
|
27
27
|
const [value, setValue] = useState<IPhoneValue>({
|
|
28
28
|
dialCode: '7',
|
|
29
|
-
phoneNumber: '
|
|
29
|
+
phoneNumber: '9134567890',
|
|
30
|
+
countryCode: 'RU',
|
|
30
31
|
});
|
|
31
32
|
|
|
32
33
|
return <PhoneInput {...args} value={value} onChange={setValue} />;
|
|
@@ -76,7 +76,7 @@ export const PhoneInput: FC<IPhoneInputProps> = ({
|
|
|
76
76
|
|
|
77
77
|
const countryCode = useMemo(
|
|
78
78
|
() => value?.countryCode ?? getCountryCodeFromPhone(phoneWithCode),
|
|
79
|
-
[value.dialCode, value.phoneNumber],
|
|
79
|
+
[value.countryCode, value.dialCode, value.phoneNumber],
|
|
80
80
|
);
|
|
81
81
|
|
|
82
82
|
const handleClose = () => {
|
|
@@ -122,7 +122,10 @@ export const PhoneInput: FC<IPhoneInputProps> = ({
|
|
|
122
122
|
if (newPhoneInfo.countryCode !== countryCode) {
|
|
123
123
|
onChange(
|
|
124
124
|
{
|
|
125
|
-
phoneNumber:
|
|
125
|
+
phoneNumber:
|
|
126
|
+
newPhoneInfo.dialCode !== value.dialCode
|
|
127
|
+
? ''
|
|
128
|
+
: getPhoneObjFromString(phoneWithCode).phoneNumber,
|
|
126
129
|
dialCode: newPhoneInfo.dialCode,
|
|
127
130
|
countryCode: newPhoneInfo.countryCode,
|
|
128
131
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { forwardRef } from 'react';
|
|
2
2
|
import { getTestId } from '@true-engineering/true-react-platform-helpers';
|
|
3
3
|
import { useTweakStyles } from '../../hooks';
|
|
4
4
|
import { ICommonProps } from '../../types';
|
|
@@ -11,31 +11,26 @@ export type ISearchInputProps = Omit<
|
|
|
11
11
|
> &
|
|
12
12
|
ICommonProps<ISearchInputStyles>;
|
|
13
13
|
|
|
14
|
-
export const SearchInput
|
|
15
|
-
isClearable = true,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}) => {
|
|
23
|
-
const tweakInputStyles = useTweakStyles({
|
|
24
|
-
innerStyles: inputStyles,
|
|
25
|
-
tweakStyles,
|
|
26
|
-
className: 'tweakInput',
|
|
27
|
-
currentComponentName: 'SearchInput',
|
|
28
|
-
});
|
|
14
|
+
export const SearchInput = forwardRef<HTMLInputElement, ISearchInputProps>(
|
|
15
|
+
({ isClearable = true, placeholder, value, testId, tweakStyles, data, ...props }, ref) => {
|
|
16
|
+
const tweakInputStyles = useTweakStyles({
|
|
17
|
+
innerStyles: inputStyles,
|
|
18
|
+
tweakStyles,
|
|
19
|
+
className: 'tweakInput',
|
|
20
|
+
currentComponentName: 'SearchInput',
|
|
21
|
+
});
|
|
29
22
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
23
|
+
return (
|
|
24
|
+
<Input
|
|
25
|
+
ref={ref}
|
|
26
|
+
value={value}
|
|
27
|
+
placeholder={placeholder}
|
|
28
|
+
icon="search"
|
|
29
|
+
isClearable={isClearable}
|
|
30
|
+
testId={getTestId(testId, 'input')}
|
|
31
|
+
tweakStyles={tweakInputStyles}
|
|
32
|
+
{...props}
|
|
33
|
+
/>
|
|
34
|
+
);
|
|
35
|
+
},
|
|
36
|
+
);
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
KeyboardEvent,
|
|
6
6
|
MouseEvent,
|
|
7
7
|
ReactNode,
|
|
8
|
+
Ref,
|
|
8
9
|
SyntheticEvent,
|
|
9
10
|
useCallback,
|
|
10
11
|
useEffect,
|
|
@@ -63,7 +64,11 @@ export interface ISelectProps<Value>
|
|
|
63
64
|
/** @default true */
|
|
64
65
|
shouldScrollToList?: boolean;
|
|
65
66
|
isMultiSelect?: false;
|
|
66
|
-
searchInput?: {
|
|
67
|
+
searchInput?: {
|
|
68
|
+
/** @default false */
|
|
69
|
+
shouldRenderInList?: boolean;
|
|
70
|
+
ref?: Ref<HTMLInputElement>;
|
|
71
|
+
} & Pick<ISearchInputProps, 'placeholder' | 'shouldFocusOnMount'>;
|
|
67
72
|
isOptionDisabled?: (option: Value) => boolean;
|
|
68
73
|
onChange: (value: Value | undefined, event: IChangeSelectEvent) => void; // подумать как возвращать индекс
|
|
69
74
|
onBlur?: (event: Event | SyntheticEvent) => void;
|
|
@@ -248,10 +253,14 @@ export function Select<Value>(
|
|
|
248
253
|
|
|
249
254
|
const handleListClose = useCallback(
|
|
250
255
|
(event: Event | SyntheticEvent) => {
|
|
256
|
+
if (!isListOpen) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
|
|
251
260
|
closeList();
|
|
252
261
|
onBlur?.(event);
|
|
253
262
|
},
|
|
254
|
-
[closeList, onBlur],
|
|
263
|
+
[isListOpen, closeList, onBlur],
|
|
255
264
|
);
|
|
256
265
|
|
|
257
266
|
const handleListOpen = () => {
|
|
@@ -8,7 +8,7 @@ import { useStyles, ITooltipStyles } from './Tooltip.styles';
|
|
|
8
8
|
export interface ITooltipProps extends ICommonProps<ITooltipStyles> {
|
|
9
9
|
text: ReactNode;
|
|
10
10
|
/** @default 'tooltip' */
|
|
11
|
-
view?: 'tooltip' | 'hint';
|
|
11
|
+
view?: 'tooltip' | 'hint' | 'custom';
|
|
12
12
|
/** @default 'info' */
|
|
13
13
|
type?: 'info' | 'error';
|
|
14
14
|
}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import type { IPhoneInfo } from '../components';
|
|
2
2
|
|
|
3
3
|
export const phoneInfo: IPhoneInfo[] = [
|
|
4
|
+
{
|
|
5
|
+
countryEn: 'Abkhazia',
|
|
6
|
+
countryRu: 'Абхазия',
|
|
7
|
+
countryCode: 'AB',
|
|
8
|
+
phoneMask: '(999) 999-99-99',
|
|
9
|
+
dialCode: '7',
|
|
10
|
+
dialCodePriority: 1,
|
|
11
|
+
fullCodes: ['7'],
|
|
12
|
+
},
|
|
4
13
|
{
|
|
5
14
|
countryEn: 'Afghanistan',
|
|
6
15
|
countryRu: 'Афганистан',
|
|
@@ -785,40 +794,9 @@ export const phoneInfo: IPhoneInfo[] = [
|
|
|
785
794
|
countryRu: 'Казахстан',
|
|
786
795
|
countryCode: 'KZ',
|
|
787
796
|
dialCode: '7',
|
|
788
|
-
phoneMask: '999 999-99-99',
|
|
797
|
+
phoneMask: '(999) 999-99-99',
|
|
789
798
|
dialCodePriority: 1,
|
|
790
|
-
|
|
791
|
-
'310',
|
|
792
|
-
'311',
|
|
793
|
-
'312',
|
|
794
|
-
'313',
|
|
795
|
-
'315',
|
|
796
|
-
'318',
|
|
797
|
-
'321',
|
|
798
|
-
'324',
|
|
799
|
-
'325',
|
|
800
|
-
'326',
|
|
801
|
-
'327',
|
|
802
|
-
'336',
|
|
803
|
-
'7172',
|
|
804
|
-
'73622',
|
|
805
|
-
],
|
|
806
|
-
fullCodes: [
|
|
807
|
-
'7310',
|
|
808
|
-
'7311',
|
|
809
|
-
'7312',
|
|
810
|
-
'7313',
|
|
811
|
-
'7315',
|
|
812
|
-
'7318',
|
|
813
|
-
'7321',
|
|
814
|
-
'7324',
|
|
815
|
-
'7325',
|
|
816
|
-
'7326',
|
|
817
|
-
'7327',
|
|
818
|
-
'7336',
|
|
819
|
-
'77172',
|
|
820
|
-
'773622',
|
|
821
|
-
],
|
|
799
|
+
fullCodes: ['7'],
|
|
822
800
|
},
|
|
823
801
|
{
|
|
824
802
|
countryEn: 'Kenya',
|
|
@@ -1404,6 +1382,15 @@ export const phoneInfo: IPhoneInfo[] = [
|
|
|
1404
1382
|
phoneMask: '999 9999 9999',
|
|
1405
1383
|
fullCodes: ['82'],
|
|
1406
1384
|
},
|
|
1385
|
+
{
|
|
1386
|
+
countryCode: 'OS',
|
|
1387
|
+
countryEn: 'South Ossetia',
|
|
1388
|
+
countryRu: 'Южная Осетия',
|
|
1389
|
+
phoneMask: '(999) 999-99-99',
|
|
1390
|
+
dialCode: '7',
|
|
1391
|
+
dialCodePriority: 1,
|
|
1392
|
+
fullCodes: ['7'],
|
|
1393
|
+
},
|
|
1407
1394
|
{
|
|
1408
1395
|
countryEn: 'South Sudan',
|
|
1409
1396
|
countryRu: 'Южный Судан',
|
package/src/helpers/phone.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isNotEmpty,
|
|
1
|
+
import { isNotEmpty, isStringEmpty } from '@true-engineering/true-react-platform-helpers';
|
|
2
2
|
import type { IPhoneInfo, IPhoneValue } from '../components';
|
|
3
3
|
import { phoneInfo } from '../constants';
|
|
4
4
|
|
|
@@ -46,22 +46,26 @@ export const getFullPhone = (phone?: IPhoneValue): string =>
|
|
|
46
46
|
(phone?.dialCode ?? '') + (phone?.phoneNumber ?? '');
|
|
47
47
|
|
|
48
48
|
export const getCountryCodeFromPhone = (phoneWithCode: string): string | undefined => {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
info.fullCodes.some((code) => phoneWithCode.startsWith(code)),
|
|
52
|
-
)?.countryCode;
|
|
53
|
-
|
|
54
|
-
if (isEmpty(countryCode) && isNotEmpty(phoneWithCode)) {
|
|
55
|
-
// если не нашли уникальный fullCode (dialCode + arealCode),
|
|
56
|
-
// то пробуем найти dialCode и выбираем с наименьшим Priority
|
|
57
|
-
countryCode = phoneInfo
|
|
58
|
-
.filter((info) => phoneWithCode.startsWith(info.dialCode))
|
|
59
|
-
.sort(
|
|
60
|
-
(infoA, infoB) => (infoA.dialCodePriority ?? 1000) - (infoB.dialCodePriority ?? 1000),
|
|
61
|
-
)[0]?.countryCode;
|
|
49
|
+
if (isStringEmpty(phoneWithCode)) {
|
|
50
|
+
return;
|
|
62
51
|
}
|
|
63
52
|
|
|
64
|
-
|
|
53
|
+
// ищем страны, для которых phoneWithCode начинается с fullCode (dialCode + areaCode)
|
|
54
|
+
const matchedCountries = phoneInfo.filter((info) =>
|
|
55
|
+
info.fullCodes.some((fullCode) => phoneWithCode.startsWith(fullCode)),
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
// если нашлась всего одна — ок, выдаём её
|
|
59
|
+
if (matchedCountries.length === 1) {
|
|
60
|
+
return matchedCountries[0].countryCode;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// если нашлось несколько, выбираем страну с наименьшим dialCodePriority (0 — самая приоритетная)
|
|
64
|
+
const highestPriorityCountries = phoneInfo
|
|
65
|
+
.filter((info) => phoneWithCode.startsWith(info.dialCode))
|
|
66
|
+
.sort((a, b) => (a.dialCodePriority ?? 1000) - (b.dialCodePriority ?? 1000));
|
|
67
|
+
|
|
68
|
+
return highestPriorityCountries.at(0)?.countryCode;
|
|
65
69
|
};
|
|
66
70
|
|
|
67
71
|
export const getPhoneObjFromString = (fullPhone: string, countryCode?: string): IPhoneValue => {
|