@true-engineering/true-react-common-ui-kit 4.0.0-alpha5 → 4.0.0-alpha7
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 +117 -4
- package/dist/components/Button/Button.styles.d.ts +1 -1
- package/dist/components/Checkbox/Checkbox.styles.d.ts +1 -1
- package/dist/components/DatePicker/DatePicker.d.ts +2 -2
- package/dist/components/DatePicker/helpers.d.ts +3 -0
- package/dist/components/DatePicker/types.d.ts +3 -1
- package/dist/components/FiltersPane/FiltersPane.d.ts +4 -2
- package/dist/components/FiltersPane/FiltersPane.stories.d.ts +3 -3
- package/dist/components/FiltersPane/components/Filter/Filter.d.ts +2 -2
- package/dist/components/FiltersPane/components/Filter/helpers.d.ts +4 -0
- package/dist/components/FiltersPane/components/FilterInterval/FilterInterval.styles.d.ts +1 -1
- package/dist/components/FiltersPane/components/FilterSelect/FilterSelect.styles.d.ts +1 -1
- package/dist/components/FiltersPane/components/FilterValueView/FilterValueView.d.ts +3 -1
- package/dist/components/FiltersPane/components/FilterWithDates/FilterWithDates.styles.d.ts +2 -2
- package/dist/components/FiltersPane/components/FilterWrapper/FilterWrapper.d.ts +2 -2
- 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 +4 -2
- package/dist/components/FlexibleTable/components/FlexibleTableRow/FlexibleTableRow.d.ts +6 -6
- 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/Select/Select.styles.d.ts +2 -2
- package/dist/components/Tooltip/Tooltip.d.ts +1 -1
- package/dist/components/Tooltip/Tooltip.styles.d.ts +1 -1
- package/dist/components/WithMessages/WithMessages.styles.d.ts +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/use-merge.d.ts +1 -0
- package/dist/hooks/use-mixed-styles.d.ts +3 -1
- package/dist/hooks/use-tweak-styles.d.ts +5 -5
- package/dist/theme/Provider.d.ts +6 -3
- package/dist/theme/create-themed-styles.d.ts +2 -0
- package/dist/theme/helpers.d.ts +9 -3
- package/dist/theme/index.d.ts +2 -0
- package/dist/theme/true-jss/ThemedStylesManager.d.ts +18 -0
- package/dist/theme/true-jss/TweakStylesManager.d.ts +34 -0
- package/dist/theme/true-jss/index.d.ts +2 -0
- package/dist/theme/true-jss/jss-context.d.ts +9 -0
- package/dist/theme/types.d.ts +4 -2
- package/dist/true-react-common-ui-kit.js +6736 -5801
- package/dist/true-react-common-ui-kit.js.map +1 -1
- package/dist/true-react-common-ui-kit.umd.cjs +6866 -5932
- package/dist/true-react-common-ui-kit.umd.cjs.map +1 -1
- package/dist/types.d.ts +2 -1
- package/package.json +1 -1
- package/src/components/DatePicker/DatePicker.tsx +9 -4
- package/src/components/DatePicker/helpers.ts +13 -1
- package/src/components/DatePicker/types.ts +4 -1
- package/src/components/FiltersPane/FiltersPane.stories.tsx +4 -2
- package/src/components/FiltersPane/FiltersPane.tsx +14 -9
- package/src/components/FiltersPane/components/Filter/Filter.tsx +24 -17
- package/src/components/FiltersPane/components/Filter/helpers.ts +18 -0
- package/src/components/FiltersPane/components/FilterValueView/FilterValueView.tsx +27 -22
- package/src/components/FiltersPane/components/FilterWithDates/FilterWithDates.styles.ts +1 -0
- package/src/components/FiltersPane/components/FilterWithPeriod/FilterWithPeriod.tsx +1 -1
- package/src/components/FiltersPane/components/FilterWrapper/FilterWrapper.tsx +7 -5
- 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 +13 -12
- package/src/components/FlexibleTable/components/FlexibleTableRow/FlexibleTableRow.tsx +9 -8
- 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/src/hooks/index.ts +1 -0
- package/src/hooks/use-merge.ts +8 -0
- package/src/hooks/use-mixed-styles.ts +9 -11
- package/src/hooks/use-tweak-styles.ts +49 -27
- package/src/theme/Provider.tsx +10 -5
- package/src/theme/create-themed-styles.ts +78 -0
- package/src/theme/helpers.ts +39 -39
- package/src/theme/index.ts +2 -0
- package/src/theme/true-jss/ThemedStylesManager.ts +92 -0
- package/src/theme/true-jss/TweakStylesManager.ts +157 -0
- package/src/theme/true-jss/index.ts +2 -0
- package/src/theme/true-jss/jss-context.tsx +34 -0
- package/src/theme/types.ts +4 -2
- package/src/types.ts +2 -1
|
@@ -34,10 +34,10 @@ export interface IFlexibleTableProps<
|
|
|
34
34
|
| 'uniqueField'
|
|
35
35
|
| 'rowAttributes'
|
|
36
36
|
| 'isFirstColumnSticky'
|
|
37
|
-
| 'isExpandableRowComponentInitiallyOpen'
|
|
38
37
|
| 'expandableRowComponent'
|
|
39
38
|
| 'onRowClick'
|
|
40
39
|
| 'onRowHover'
|
|
40
|
+
| 'rowRef'
|
|
41
41
|
> {
|
|
42
42
|
content: Row[];
|
|
43
43
|
/** @default 'table' */
|
|
@@ -62,6 +62,8 @@ export interface IFlexibleTableProps<
|
|
|
62
62
|
nothingFoundContent?: ReactNode;
|
|
63
63
|
/** @default true */
|
|
64
64
|
shouldRenderHeader?: boolean;
|
|
65
|
+
/** @default false */
|
|
66
|
+
isExpandableRowComponentInitiallyOpen?: boolean | ((row: Row, index: number) => boolean);
|
|
65
67
|
}
|
|
66
68
|
|
|
67
69
|
export function FlexibleTable<
|
|
@@ -88,6 +90,7 @@ export function FlexibleTable<
|
|
|
88
90
|
tweakStyles,
|
|
89
91
|
shouldRenderHeader = true,
|
|
90
92
|
onHeadClick,
|
|
93
|
+
isExpandableRowComponentInitiallyOpen: isRowInitiallyOpen,
|
|
91
94
|
...restProps
|
|
92
95
|
}: IFlexibleTableProps<Row, HeaderContent, UniqueField>): JSX.Element {
|
|
93
96
|
const classes = useStyles({ theme: tweakStyles });
|
|
@@ -105,11 +108,12 @@ export function FlexibleTable<
|
|
|
105
108
|
|
|
106
109
|
const hasInfiniteScroll = isNotEmpty(infinityScrollConfig);
|
|
107
110
|
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
>
|
|
111
|
+
const getTableRowProps = (
|
|
112
|
+
item: Row,
|
|
113
|
+
index: number,
|
|
114
|
+
): IFlexibleTableRowProps<Row, HeaderContent, UniqueField> => ({
|
|
112
115
|
...restProps,
|
|
116
|
+
item,
|
|
113
117
|
renderMode,
|
|
114
118
|
config,
|
|
115
119
|
columns,
|
|
@@ -118,7 +122,8 @@ export function FlexibleTable<
|
|
|
118
122
|
isFirstColumnSticky,
|
|
119
123
|
isFocusable: isRowFocusable,
|
|
120
124
|
tweakStyles: tweakTableRowStyles,
|
|
121
|
-
|
|
125
|
+
isExpandableRowComponentInitiallyOpen: applyAction(isRowInitiallyOpen, item, index),
|
|
126
|
+
});
|
|
122
127
|
|
|
123
128
|
const getDataScrollAttributeSetter = useCallback(
|
|
124
129
|
(key: string, setter: (el: HTMLDivElement) => boolean) => (el?: HTMLDivElement) => {
|
|
@@ -267,9 +272,7 @@ export function FlexibleTable<
|
|
|
267
272
|
)}
|
|
268
273
|
<Table.Body className={classes.body}>
|
|
269
274
|
{isLoading ? (
|
|
270
|
-
indexMap(6, (i) => (
|
|
271
|
-
<FlexibleTableRow {...tableRowProps} key={i} item={{} as Row} index={i} />
|
|
272
|
-
))
|
|
275
|
+
indexMap(6, (i) => <FlexibleTableRow {...getTableRowProps({} as Row, i)} key={i} />)
|
|
273
276
|
) : (
|
|
274
277
|
<>
|
|
275
278
|
{shouldShowNothingFound && (
|
|
@@ -282,11 +285,9 @@ export function FlexibleTable<
|
|
|
282
285
|
|
|
283
286
|
{content.map((item, i) => (
|
|
284
287
|
<FlexibleTableRow
|
|
285
|
-
{...
|
|
288
|
+
{...getTableRowProps(item, i)}
|
|
286
289
|
isActive={activeRowsSet.has(i)}
|
|
287
290
|
key={isNotEmpty(uniqueField) ? item[uniqueField] : i}
|
|
288
|
-
item={item}
|
|
289
|
-
index={i}
|
|
290
291
|
/>
|
|
291
292
|
))}
|
|
292
293
|
|
|
@@ -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
|
-
import {
|
|
3
|
+
import { 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,9 +19,8 @@ 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
|
-
index: number;
|
|
25
24
|
uniqueField?: UniqueField;
|
|
26
25
|
renderMode: IFlexibleTableRenderMode;
|
|
27
26
|
/** @default false */
|
|
@@ -37,7 +36,8 @@ export interface IFlexibleTableRowProps<
|
|
|
37
36
|
columns: Array<keyof Row & string>;
|
|
38
37
|
rowAttributes?: Array<keyof Row>;
|
|
39
38
|
/** @default false */
|
|
40
|
-
isExpandableRowComponentInitiallyOpen?: boolean
|
|
39
|
+
isExpandableRowComponentInitiallyOpen?: boolean;
|
|
40
|
+
rowRef?: RefCallback<HTMLTableRowElement>;
|
|
41
41
|
/** Возвращает React-элемент, который отрисуется под строкой при нажатии на неё */
|
|
42
42
|
expandableRowComponent?: (item: Row, isOpen: boolean, close: () => void) => ReactNode;
|
|
43
43
|
onRowHover?: (id?: Row[UniqueField]) => void;
|
|
@@ -50,7 +50,6 @@ function FlexibleTableRowInner<
|
|
|
50
50
|
UniqueField extends keyof Row,
|
|
51
51
|
>({
|
|
52
52
|
item,
|
|
53
|
-
index,
|
|
54
53
|
config,
|
|
55
54
|
columns,
|
|
56
55
|
uniqueField,
|
|
@@ -61,6 +60,7 @@ function FlexibleTableRowInner<
|
|
|
61
60
|
isLoading = false,
|
|
62
61
|
rowAttributes,
|
|
63
62
|
isExpandableRowComponentInitiallyOpen = false,
|
|
63
|
+
rowRef,
|
|
64
64
|
tweakStyles,
|
|
65
65
|
expandableRowComponent,
|
|
66
66
|
onRowHover,
|
|
@@ -76,7 +76,7 @@ function FlexibleTableRowInner<
|
|
|
76
76
|
|
|
77
77
|
const [isFocused, setFocused] = useState(false);
|
|
78
78
|
const [nestedComponent, setNestedComponent] = useState<INestedComponent>(() => ({
|
|
79
|
-
isOpen:
|
|
79
|
+
isOpen: isExpandableRowComponentInitiallyOpen,
|
|
80
80
|
}));
|
|
81
81
|
|
|
82
82
|
const isEditable = !isLoading && (isNotEmpty(onRowClick) || isNotEmpty(onRowHover));
|
|
@@ -139,6 +139,7 @@ function FlexibleTableRowInner<
|
|
|
139
139
|
return (
|
|
140
140
|
<>
|
|
141
141
|
<Table.Row
|
|
142
|
+
ref={rowRef}
|
|
142
143
|
className={clsx(classes.root, {
|
|
143
144
|
[classes.active]: isActive,
|
|
144
145
|
[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 => {
|
package/src/hooks/index.ts
CHANGED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { isNotEmpty, mergeStyles } from '@true-engineering/true-react-platform-helpers';
|
|
3
|
+
|
|
4
|
+
export const useMerge = <T>(one?: T, two?: T): T | undefined =>
|
|
5
|
+
useMemo(
|
|
6
|
+
() => (isNotEmpty(one) && isNotEmpty(two) ? mergeStyles(one, two) : one ?? two),
|
|
7
|
+
[one, two],
|
|
8
|
+
);
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { isObject } from '@true-engineering/true-react-platform-helpers';
|
|
3
|
+
import type { IMixedStyles } from '../theme';
|
|
4
|
+
|
|
5
|
+
export const mixStyles = <T>(...tweakStyles: Array<IMixedStyles<T>>): Array<NonNullable<T>> =>
|
|
6
|
+
tweakStyles.flat().filter(isObject) as Array<NonNullable<T>>;
|
|
3
7
|
|
|
4
8
|
export const useMixedStyles = <StyleSheet>(
|
|
5
|
-
baseStyles?: StyleSheet
|
|
6
|
-
tweakStyles?: StyleSheet
|
|
7
|
-
): StyleSheet
|
|
8
|
-
useMemo(
|
|
9
|
-
() =>
|
|
10
|
-
isNotEmpty(baseStyles) && isNotEmpty(tweakStyles)
|
|
11
|
-
? mergeStyles(baseStyles, tweakStyles)
|
|
12
|
-
: baseStyles ?? tweakStyles,
|
|
13
|
-
[baseStyles, tweakStyles],
|
|
14
|
-
);
|
|
9
|
+
baseStyles?: IMixedStyles<StyleSheet>,
|
|
10
|
+
tweakStyles?: IMixedStyles<StyleSheet>,
|
|
11
|
+
): Array<NonNullable<StyleSheet>> =>
|
|
12
|
+
useMemo(() => mixStyles(baseStyles, tweakStyles), [baseStyles, tweakStyles]);
|
|
@@ -1,11 +1,24 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { useContext, useMemo } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
isArrayNotEmpty,
|
|
4
|
+
isNotEmpty,
|
|
5
|
+
mergeStyles,
|
|
6
|
+
} from '@true-engineering/true-react-platform-helpers';
|
|
7
|
+
import {
|
|
8
|
+
areStylesThemed,
|
|
9
|
+
themedStyles,
|
|
10
|
+
IComponentName,
|
|
11
|
+
IMaybeArray,
|
|
12
|
+
useTheme,
|
|
13
|
+
JssContext,
|
|
14
|
+
IMixedStyles,
|
|
15
|
+
} from '../theme';
|
|
16
|
+
import { mixStyles } from './use-mixed-styles';
|
|
4
17
|
|
|
5
18
|
// TODO: Можно усилить типы
|
|
6
19
|
export const useTweakStyles = <StyleSheet, ClassName extends keyof StyleSheet & `tweak${string}`>({
|
|
7
20
|
innerStyles,
|
|
8
|
-
tweakStyles
|
|
21
|
+
tweakStyles,
|
|
9
22
|
className,
|
|
10
23
|
currentComponentName,
|
|
11
24
|
}: {
|
|
@@ -13,12 +26,12 @@ export const useTweakStyles = <StyleSheet, ClassName extends keyof StyleSheet &
|
|
|
13
26
|
* Это tweakStyles, определенные в родительском компоненте
|
|
14
27
|
* (например, стили для Input, определенные в стилях компонента Select)
|
|
15
28
|
*/
|
|
16
|
-
innerStyles?: StyleSheet[ClassName]
|
|
29
|
+
innerStyles?: IMixedStyles<StyleSheet[ClassName]>;
|
|
17
30
|
/**
|
|
18
31
|
* Пропса tweakStyles из родительского компонента
|
|
19
32
|
* (это уже непосредственно ISelectProps.tweakStyles)
|
|
20
33
|
*/
|
|
21
|
-
tweakStyles?: StyleSheet
|
|
34
|
+
tweakStyles?: IMaybeArray<StyleSheet>;
|
|
22
35
|
/**
|
|
23
36
|
* Класс для переопределения tweakStyles из-вне. (Например, 'tweakInput')
|
|
24
37
|
*/
|
|
@@ -27,31 +40,40 @@ export const useTweakStyles = <StyleSheet, ClassName extends keyof StyleSheet &
|
|
|
27
40
|
* Название компонента который вызывает useTweakStyles. (В данном примере 'Select')
|
|
28
41
|
*/
|
|
29
42
|
currentComponentName?: IComponentName;
|
|
30
|
-
}): StyleSheet[ClassName] =>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
43
|
+
}): Array<NonNullable<StyleSheet[ClassName]>> => {
|
|
44
|
+
const theme = useTheme();
|
|
45
|
+
const isMergeDisabled = isNotEmpty(useContext(JssContext).tweakStylesArch);
|
|
46
|
+
|
|
47
|
+
return useMemo(() => {
|
|
34
48
|
const themeStyles = isNotEmpty(currentComponentName)
|
|
35
|
-
? (theme.components?.[currentComponentName]
|
|
49
|
+
? (theme.components?.[currentComponentName] as StyleSheet)
|
|
36
50
|
: undefined;
|
|
37
|
-
const tweakStyles = currentComponentTweakStyles?.[className];
|
|
38
51
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
52
|
+
const resultStyles = mixStyles(
|
|
53
|
+
innerStyles,
|
|
54
|
+
mixStyles(themeStyles, tweakStyles).map((style) => style[className]),
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
if (isMergeDisabled || resultStyles.length < 2) {
|
|
58
|
+
return resultStyles;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const [maybeInnerStyles, maybeThemeStyles, ...rest] = resultStyles;
|
|
62
|
+
|
|
63
|
+
if (
|
|
64
|
+
maybeThemeStyles !== themeStyles?.[className] || // Если нет themeStyles или innerStyles
|
|
65
|
+
isArrayNotEmpty(rest) // Или есть tweakStyles
|
|
66
|
+
) {
|
|
67
|
+
// Мёржим как есть
|
|
68
|
+
return [mergeStyles(maybeInnerStyles, maybeThemeStyles, ...rest)];
|
|
43
69
|
}
|
|
44
70
|
|
|
45
|
-
//
|
|
46
|
-
if (
|
|
47
|
-
|
|
71
|
+
// Иначе мёржим themeStyles в innerStyles
|
|
72
|
+
if (!areStylesThemed(maybeInnerStyles)) {
|
|
73
|
+
themedStyles(maybeInnerStyles, maybeThemeStyles);
|
|
48
74
|
}
|
|
49
75
|
|
|
50
|
-
//
|
|
51
|
-
return
|
|
52
|
-
}, [
|
|
53
|
-
|
|
54
|
-
className,
|
|
55
|
-
currentComponentName,
|
|
56
|
-
currentComponentTweakStyles,
|
|
57
|
-
]) as StyleSheet[ClassName];
|
|
76
|
+
// И возвращаем только innerStyles
|
|
77
|
+
return [maybeInnerStyles];
|
|
78
|
+
}, [innerStyles, className, currentComponentName, tweakStyles, theme, isMergeDisabled]);
|
|
79
|
+
};
|
package/src/theme/Provider.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createContext, FC, ReactNode } from 'react';
|
|
1
|
+
import { createContext, FC, ReactNode, useContext, useMemo } from 'react';
|
|
2
2
|
import { common } from './common';
|
|
3
|
-
import { IUiKitTheme } from './types';
|
|
3
|
+
import type { IUiKitTheme } from './types';
|
|
4
4
|
|
|
5
5
|
export interface IThemedProviderProps {
|
|
6
6
|
theme: IUiKitTheme;
|
|
@@ -11,11 +11,16 @@ let globalTheme: IUiKitTheme;
|
|
|
11
11
|
|
|
12
12
|
export const getTheme = (): IUiKitTheme => globalTheme;
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
interface ThemeContextValue {
|
|
15
15
|
theme: IUiKitTheme;
|
|
16
|
-
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const ThemeContext = createContext<ThemeContextValue>({ theme: common });
|
|
17
19
|
|
|
18
20
|
export const ThemeProvider: FC<IThemedProviderProps> = ({ theme, children }) => {
|
|
19
21
|
globalTheme = theme;
|
|
20
|
-
|
|
22
|
+
const value: ThemeContextValue = useMemo(() => ({ theme }), [theme]);
|
|
23
|
+
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
|
|
21
24
|
};
|
|
25
|
+
|
|
26
|
+
export const useTheme = (): IUiKitTheme => useContext(ThemeContext).theme;
|