@true-engineering/true-react-common-ui-kit 4.0.0-alpha67 → 4.0.0-alpha69
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/components/FiltersPane/components/FilterValueView/FilterValueView.d.ts +5 -3
- package/dist/components/FiltersPane/components/FilterWrapper/helpers.d.ts +1 -1
- package/dist/components/FiltersPane/types.d.ts +0 -1
- package/dist/components/Notification/Notification.d.ts +3 -3
- package/dist/true-react-common-ui-kit.js +56 -76
- package/dist/true-react-common-ui-kit.js.map +1 -1
- package/dist/true-react-common-ui-kit.umd.cjs +1 -1
- package/dist/true-react-common-ui-kit.umd.cjs.map +1 -1
- package/package.json +1 -1
- package/src/components/FiltersPane/FiltersPane.stories.tsx +2 -1
- package/src/components/FiltersPane/components/FilterValueView/FilterValueView.tsx +61 -92
- package/src/components/FiltersPane/components/FilterWithPeriod/FilterWithPeriod.tsx +1 -1
- package/src/components/FiltersPane/components/FilterWrapper/FilterWrapper.tsx +2 -7
- package/src/components/FiltersPane/components/FilterWrapper/helpers.ts +1 -1
- package/src/components/FiltersPane/types.ts +0 -1
- package/src/components/Notification/Notification.stories.tsx +3 -1
- package/src/components/Notification/Notification.tsx +9 -17
package/package.json
CHANGED
|
@@ -275,7 +275,6 @@ const Story: FC<IFiltersPaneCustomProps<ConfigValues, unknown>> = ({
|
|
|
275
275
|
]}
|
|
276
276
|
filtersConfig={config}
|
|
277
277
|
values={values}
|
|
278
|
-
localeKey="ru"
|
|
279
278
|
locale={{ searchPlaceholder: 'Поиск' }}
|
|
280
279
|
onChangeFilters={setValues}
|
|
281
280
|
onSettingsButtonClick={shouldShowSettingsButton ? () => null : undefined}
|
|
@@ -289,6 +288,7 @@ const meta: Meta<typeof Story> = {
|
|
|
289
288
|
title: 'Table/FiltersPane',
|
|
290
289
|
component: Story,
|
|
291
290
|
args: {
|
|
291
|
+
localeKey: 'ru',
|
|
292
292
|
shouldShowSettingsButton: false,
|
|
293
293
|
isSearchDisabled: false,
|
|
294
294
|
hasClearButton: true,
|
|
@@ -302,6 +302,7 @@ const meta: Meta<typeof Story> = {
|
|
|
302
302
|
isSearchAutoSized: false,
|
|
303
303
|
},
|
|
304
304
|
argTypes: {
|
|
305
|
+
localeKey: { control: 'inline-radio', options: ['ru', 'en'] },
|
|
305
306
|
containerWidth: {
|
|
306
307
|
control: { type: 'range', min: 500, max: 1400, step: 100 },
|
|
307
308
|
},
|
|
@@ -1,17 +1,23 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
1
|
+
import { ReactNode, useMemo } from 'react';
|
|
2
2
|
import { format } from 'date-fns';
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
isArrayNotEmpty,
|
|
5
|
+
isNotEmpty,
|
|
6
|
+
isObject,
|
|
7
|
+
} from '@true-engineering/true-react-platform-helpers';
|
|
8
|
+
import { ITweakStylesProps } from '../../../../types';
|
|
5
9
|
import { IMultiSelectListValues } from '../../../MultiSelectList';
|
|
6
10
|
import { DEFAULT_DATE_FORMAT } from '../../constants';
|
|
7
|
-
import {
|
|
8
|
-
import { IDateRangeConfigItem,
|
|
11
|
+
import { getLocale } from '../../helpers';
|
|
12
|
+
import { IDateRangeConfigItem, IPeriod } from '../../types';
|
|
9
13
|
import type { IFilterWrapperProps } from '../FilterWrapper';
|
|
10
14
|
import { IFilterValueViewStyles, useStyles } from './FilterValueView.styles';
|
|
11
15
|
|
|
12
16
|
export interface IFilterValueView<Values extends Record<string, unknown>, Key extends keyof Values>
|
|
13
|
-
extends
|
|
14
|
-
|
|
17
|
+
extends Pick<IFilterWrapperProps<Values, Key>, 'value' | 'filter' | 'localeKey' | 'locale'>,
|
|
18
|
+
ITweakStylesProps<IFilterValueViewStyles> {
|
|
19
|
+
value: Values[Key];
|
|
20
|
+
}
|
|
15
21
|
|
|
16
22
|
export function FilterValueView<Values extends Record<string, unknown>, Key extends keyof Values>({
|
|
17
23
|
value,
|
|
@@ -19,8 +25,8 @@ export function FilterValueView<Values extends Record<string, unknown>, Key exte
|
|
|
19
25
|
locale,
|
|
20
26
|
localeKey,
|
|
21
27
|
tweakStyles,
|
|
22
|
-
}: IFilterValueView<Values, Key>):
|
|
23
|
-
const classes = useStyles({
|
|
28
|
+
}: IFilterValueView<Values, Key>): ReactNode {
|
|
29
|
+
const classes = useStyles({ tweakStyles });
|
|
24
30
|
|
|
25
31
|
const translatesLocaleKey = filter.localeKey ?? localeKey;
|
|
26
32
|
const translates = useMemo(
|
|
@@ -28,36 +34,26 @@ export function FilterValueView<Values extends Record<string, unknown>, Key exte
|
|
|
28
34
|
[translatesLocaleKey, locale, filter.locale],
|
|
29
35
|
);
|
|
30
36
|
|
|
31
|
-
if (isEmpty(value)) {
|
|
32
|
-
return <></>;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
37
|
if (isNotEmpty(filter.getSelectedValueView)) {
|
|
36
38
|
return <span className={classes.text}>{filter.getSelectedValueView(value)}</span>;
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
const isMultiple = filter.type === 'custom' && filter.valueViewType === 'multiple';
|
|
40
|
-
const isRange = filter.type === 'custom' && filter.valueViewType === 'range';
|
|
41
|
-
const isDateRange = filter.type === 'dateRange' || filter.type === 'dateRangeWithoutPeriod';
|
|
42
|
-
|
|
43
41
|
const displayValue = (v: unknown): string => {
|
|
44
42
|
if (!isNotEmpty(v)) {
|
|
45
43
|
return '';
|
|
46
44
|
}
|
|
47
45
|
|
|
48
46
|
if (v instanceof Date) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
(filter as IDateRangeConfigItem<IFilterWithDatesValue>).dateFormat || DEFAULT_DATE_FORMAT,
|
|
52
|
-
);
|
|
47
|
+
const { dateFormat = DEFAULT_DATE_FORMAT } = filter as IDateRangeConfigItem<unknown>;
|
|
48
|
+
return format(v, dateFormat);
|
|
53
49
|
}
|
|
54
50
|
|
|
55
|
-
if (
|
|
56
|
-
return String(v
|
|
51
|
+
if (!isObject(v)) {
|
|
52
|
+
return String(v);
|
|
57
53
|
}
|
|
58
54
|
|
|
59
|
-
if (
|
|
60
|
-
return String(v);
|
|
55
|
+
if ('value' in v && isNotEmpty(v.value)) {
|
|
56
|
+
return String(v.value);
|
|
61
57
|
}
|
|
62
58
|
|
|
63
59
|
console.warn(
|
|
@@ -69,99 +65,72 @@ export function FilterValueView<Values extends Record<string, unknown>, Key exte
|
|
|
69
65
|
};
|
|
70
66
|
|
|
71
67
|
if (filter.type === 'select') {
|
|
72
|
-
const getView = filter.getValueView ??
|
|
68
|
+
const getView = filter.getValueView ?? displayValue;
|
|
73
69
|
return <span className={classes.text}>{getView(value)}</span>;
|
|
74
70
|
}
|
|
75
71
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
73
|
+
const getArrayView = (values: unknown, getView: (_: any) => ReactNode = displayValue) => {
|
|
74
|
+
if (!Array.isArray(values) || !isArrayNotEmpty(values)) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
80
77
|
|
|
78
|
+
const [first, ...rest] = values;
|
|
81
79
|
return (
|
|
82
80
|
<>
|
|
83
|
-
{
|
|
84
|
-
|
|
85
|
-
<span className={classes.text}>{getView(include[0])}</span>
|
|
86
|
-
<span className={classes.count}>
|
|
87
|
-
{include.length > 1 && ` (+${include.length - 1})`}
|
|
88
|
-
</span>
|
|
89
|
-
</>
|
|
90
|
-
)}
|
|
81
|
+
<span className={classes.text}>{getView(first)}</span>
|
|
82
|
+
{isArrayNotEmpty(rest) && <span className={classes.count}> (+{rest.length})</span>}
|
|
91
83
|
</>
|
|
92
84
|
);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (filter.type === 'interval') {
|
|
96
|
-
const intervalValue = value as unknown as number[];
|
|
97
|
-
const intervalValueFrom = intervalValue[0];
|
|
98
|
-
const intervalValueTo = intervalValue[1];
|
|
85
|
+
};
|
|
99
86
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (intervalValueTo !== undefined) {
|
|
105
|
-
intervals.push(`${translates.to.toLowerCase()} ${String(intervalValueTo)}`);
|
|
106
|
-
}
|
|
87
|
+
if (filter.type === 'multiSelect') {
|
|
88
|
+
const { include } = value as Partial<IMultiSelectListValues<unknown>>;
|
|
89
|
+
return getArrayView(include, filter.getValueView);
|
|
90
|
+
}
|
|
107
91
|
|
|
108
|
-
|
|
92
|
+
const isMultiple = filter.type === 'custom' && filter.valueViewType === 'multiple';
|
|
93
|
+
if (isMultiple) {
|
|
94
|
+
return getArrayView(value, filter.getSelectedValue);
|
|
109
95
|
}
|
|
110
96
|
|
|
97
|
+
const isDateRange = filter.type === 'dateRange' || filter.type === 'dateRangeWithoutPeriod';
|
|
111
98
|
if (isDateRange) {
|
|
112
|
-
const { from, to, periodType
|
|
113
|
-
const hasFrom = from !== undefined && from !== null;
|
|
114
|
-
const hasTo = to !== undefined && to !== null;
|
|
99
|
+
const { from, to, periodType = 'CUSTOM' } = value as Partial<IPeriod>;
|
|
115
100
|
|
|
116
101
|
if (periodType !== 'CUSTOM') {
|
|
117
|
-
return <span className={classes.text}>{
|
|
102
|
+
return <span className={classes.text}>{translates.periods[periodType] ?? periodType}</span>;
|
|
118
103
|
}
|
|
119
104
|
|
|
105
|
+
const hasFrom = isNotEmpty(from);
|
|
106
|
+
const hasTo = isNotEmpty(to);
|
|
120
107
|
const range: string[] = [];
|
|
121
|
-
if (hasFrom) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
range.push('—');
|
|
130
|
-
} else {
|
|
131
|
-
range.push(translates.to.toLowerCase());
|
|
132
|
-
}
|
|
133
|
-
range.push(displayValue(to));
|
|
108
|
+
if (hasFrom && hasTo) {
|
|
109
|
+
range.push(displayValue(from), '—', displayValue(to));
|
|
110
|
+
} else if (hasFrom) {
|
|
111
|
+
range.push(translates.from.toLowerCase(), displayValue(from));
|
|
112
|
+
} else if (hasTo) {
|
|
113
|
+
range.push(translates.to.toLowerCase(), displayValue(to));
|
|
114
|
+
} else {
|
|
115
|
+
return null;
|
|
134
116
|
}
|
|
135
117
|
|
|
136
118
|
return <span className={classes.text}>{range.join(' ')}</span>;
|
|
137
119
|
}
|
|
138
120
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
{Array.isArray(value) && value.length > 0 && (
|
|
145
|
-
<>
|
|
146
|
-
<span className={classes.text}>{convertValue(value[0])}</span>
|
|
147
|
-
<span className={classes.count}>{value.length > 1 && ` (+${value.length - 1})`}</span>
|
|
148
|
-
</>
|
|
149
|
-
)}
|
|
150
|
-
</>
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (isRange && Array.isArray(value)) {
|
|
155
|
-
const rangeValue = value as unknown as number[];
|
|
156
|
-
const rangeValueFrom = rangeValue[0];
|
|
157
|
-
const rangeValueTo = rangeValue[1];
|
|
121
|
+
const isRange = filter.type === 'custom' && filter.valueViewType === 'range';
|
|
122
|
+
if (isRange || filter.type === 'interval') {
|
|
123
|
+
if (!Array.isArray(value)) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
158
126
|
|
|
127
|
+
const [valueFrom, valueTo] = value;
|
|
159
128
|
const range: string[] = [];
|
|
160
|
-
if (
|
|
161
|
-
range.push(
|
|
129
|
+
if (isNotEmpty(valueFrom)) {
|
|
130
|
+
range.push(translates.from.toLowerCase(), displayValue(valueFrom));
|
|
162
131
|
}
|
|
163
|
-
if (
|
|
164
|
-
range.push(
|
|
132
|
+
if (isNotEmpty(valueTo)) {
|
|
133
|
+
range.push(translates.to.toLowerCase(), displayValue(valueTo));
|
|
165
134
|
}
|
|
166
135
|
|
|
167
136
|
return <span className={classes.text}>{range.join(' ')}</span>;
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { MouseEventHandler } from 'react';
|
|
2
2
|
import clsx from 'clsx';
|
|
3
|
-
import {
|
|
4
|
-
addDataAttributes,
|
|
5
|
-
getTestId,
|
|
6
|
-
isNotEmpty,
|
|
7
|
-
} from '@true-engineering/true-react-platform-helpers';
|
|
3
|
+
import { addDataAttributes } from '@true-engineering/true-react-platform-helpers';
|
|
8
4
|
import { useMixedStyles, useTweakStyles } from '../../../../hooks';
|
|
9
5
|
import { ICommonProps } from '../../../../types';
|
|
10
6
|
import { Icon } from '../../../Icon';
|
|
@@ -105,14 +101,13 @@ export function FilterWrapper<Values extends Record<string, unknown>, Key extend
|
|
|
105
101
|
className={clsx(classes.item, { [classes.booleanItem]: isBoolean })}
|
|
106
102
|
>
|
|
107
103
|
<div className={classes.name}>{filter.name}</div>
|
|
108
|
-
{!isBoolean &&
|
|
104
|
+
{!isBoolean && hasValue && (
|
|
109
105
|
<div className={classes.value}>
|
|
110
106
|
<FilterValueView
|
|
111
107
|
value={value}
|
|
112
108
|
filter={filter}
|
|
113
109
|
locale={locale}
|
|
114
110
|
localeKey={localeKey}
|
|
115
|
-
testId={getTestId(testId, 'value')}
|
|
116
111
|
tweakStyles={tweakFilterValueViewStyles}
|
|
117
112
|
/>
|
|
118
113
|
</div>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isNotEmpty, isObject } from '@true-engineering/true-react-platform-helpers';
|
|
2
2
|
|
|
3
|
-
export const isContentNotEmpty = (value:
|
|
3
|
+
export const isContentNotEmpty = <T>(value: T): value is NonNullable<T> => {
|
|
4
4
|
if (Array.isArray(value)) {
|
|
5
5
|
return value.some(isContentNotEmpty);
|
|
6
6
|
}
|
|
@@ -39,7 +39,9 @@ const meta: Meta<typeof Story> = {
|
|
|
39
39
|
shouldUseChildrenInstead: false,
|
|
40
40
|
},
|
|
41
41
|
argTypes: {
|
|
42
|
-
icon: { options: [undefined, ...Object.keys(iconsMap)], control: 'select' },
|
|
42
|
+
icon: { options: [undefined, null, ...Object.keys(iconsMap)], control: 'select' },
|
|
43
|
+
size: { options: ['s', 'm', 'l'], control: 'inline-radio' },
|
|
44
|
+
type: { options: ['info', 'error', 'warning', 'ok', 'not-ok', 'custom'], control: 'select' },
|
|
43
45
|
},
|
|
44
46
|
parameters: {
|
|
45
47
|
controls: {
|
|
@@ -3,11 +3,11 @@ import clsx from 'clsx';
|
|
|
3
3
|
import {
|
|
4
4
|
addDataAttributes,
|
|
5
5
|
addDataTestId,
|
|
6
|
+
isNotEmpty,
|
|
6
7
|
isReactNodeNotEmpty,
|
|
7
|
-
isStringNotEmpty,
|
|
8
8
|
} from '@true-engineering/true-react-platform-helpers';
|
|
9
9
|
import { ICommonProps } from '../../types';
|
|
10
|
-
import {
|
|
10
|
+
import { IIcon, renderIcon } from '../Icon';
|
|
11
11
|
import { INotificationType } from './types';
|
|
12
12
|
import { useStyles, INotificationStyles } from './Notification.styles';
|
|
13
13
|
|
|
@@ -15,11 +15,11 @@ export interface INotificationProps extends ICommonProps<INotificationStyles> {
|
|
|
15
15
|
type: INotificationType;
|
|
16
16
|
/** @default true */
|
|
17
17
|
isFullWidth?: boolean;
|
|
18
|
-
text?:
|
|
19
|
-
title?:
|
|
18
|
+
text?: ReactNode;
|
|
19
|
+
title?: ReactNode;
|
|
20
20
|
/** @default 's' */
|
|
21
21
|
size?: 's' | 'm' | 'l';
|
|
22
|
-
icon?: IIcon;
|
|
22
|
+
icon?: IIcon | null;
|
|
23
23
|
children?: ReactNode;
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -32,15 +32,13 @@ export const Notification: FC<INotificationProps> = ({
|
|
|
32
32
|
testId,
|
|
33
33
|
size = 's',
|
|
34
34
|
data,
|
|
35
|
-
icon,
|
|
35
|
+
icon = type !== 'custom' ? `status-${type}` : undefined,
|
|
36
36
|
tweakStyles,
|
|
37
37
|
}) => {
|
|
38
38
|
const classes = useStyles({ theme: tweakStyles });
|
|
39
39
|
|
|
40
|
-
const hasText =
|
|
41
|
-
const hasTitle =
|
|
42
|
-
const isDefaultType = type !== 'custom';
|
|
43
|
-
const hasIcon = isReactNodeNotEmpty(icon) || isDefaultType;
|
|
40
|
+
const hasText = isReactNodeNotEmpty(text);
|
|
41
|
+
const hasTitle = isReactNodeNotEmpty(title);
|
|
44
42
|
|
|
45
43
|
return (
|
|
46
44
|
<div
|
|
@@ -51,13 +49,7 @@ export const Notification: FC<INotificationProps> = ({
|
|
|
51
49
|
})}
|
|
52
50
|
{...addDataAttributes(data, testId)}
|
|
53
51
|
>
|
|
54
|
-
{
|
|
55
|
-
<div className={classes.icon}>
|
|
56
|
-
{isReactNodeNotEmpty(icon)
|
|
57
|
-
? renderIcon(icon)
|
|
58
|
-
: isDefaultType && <Icon type={`status-${type}`} />}
|
|
59
|
-
</div>
|
|
60
|
-
)}
|
|
52
|
+
{isNotEmpty(icon) && <div className={classes.icon}>{renderIcon(icon)}</div>}
|
|
61
53
|
<div className={classes.body}>
|
|
62
54
|
{hasTitle && (
|
|
63
55
|
<span className={classes.title} {...addDataTestId(testId, 'title')}>
|