@true-engineering/true-react-common-ui-kit 4.0.0-alpha68 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@true-engineering/true-react-common-ui-kit",
3
- "version": "4.0.0-alpha68",
3
+ "version": "4.0.0-alpha69",
4
4
  "description": "True Engineering React UI Kit with theming support",
5
5
  "author": "True Engineering (https://trueengineering.ru)",
6
6
  "keywords": [
@@ -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 { isEmpty, isNotEmpty } from '@true-engineering/true-react-platform-helpers';
4
- import { ICommonProps } from '../../../../types';
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 { defaultConvertFunction, getLocale } from '../../helpers';
8
- import { IDateRangeConfigItem, IFilterWithDatesValue, IPeriod } from '../../types';
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 Omit<IFilterWrapperProps<Values, Key>, 'filtersPaneRef' | 'tweakStyles' | 'onChange'>,
14
- ICommonProps<IFilterValueViewStyles> {}
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>): JSX.Element {
23
- const classes = useStyles({ theme: tweakStyles });
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
- return format(
50
- v,
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 (typeof v === 'object' && 'value' in v && isNotEmpty(v.value)) {
56
- return String(v.value);
51
+ if (!isObject(v)) {
52
+ return String(v);
57
53
  }
58
54
 
59
- if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') {
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 ?? defaultConvertFunction;
68
+ const getView = filter.getValueView ?? displayValue;
73
69
  return <span className={classes.text}>{getView(value)}</span>;
74
70
  }
75
71
 
76
- if (filter.type === 'multiSelect') {
77
- const multiSelectValue = value as IMultiSelectListValues<any>;
78
- const getView = filter.getValueView ?? defaultConvertFunction;
79
- const { include } = multiSelectValue;
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
- {Array.isArray(include) && include.length > 0 && (
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
- const intervals: string[] = [];
101
- if (intervalValueFrom !== undefined) {
102
- intervals.push(`${translates.from.toLowerCase()} ${String(intervalValueFrom)}`);
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
- return <span className={classes.text}>{intervals.join(' ')}</span>;
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, label } = value as unknown as IPeriod;
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}>{displayValue(label)}</span>;
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
- if (!hasTo) {
123
- range.push(translates.from.toLowerCase());
124
- }
125
- range.push(displayValue(from));
126
- }
127
- if (hasTo) {
128
- if (hasFrom) {
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
- if (isMultiple) {
140
- const convertValue = filter.getSelectedValue ?? displayValue;
141
-
142
- return (
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 (rangeValueFrom !== undefined) {
161
- range.push(`${translates.from.toLowerCase()} ${String(rangeValueFrom)}`);
129
+ if (isNotEmpty(valueFrom)) {
130
+ range.push(translates.from.toLowerCase(), displayValue(valueFrom));
162
131
  }
163
- if (rangeValueTo !== undefined) {
164
- range.push(`${translates.to.toLowerCase()} ${String(rangeValueTo)}`);
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>;
@@ -86,7 +86,7 @@ export const FilterWithPeriod: FC<IFilterWithPeriodProps> = ({
86
86
  if (onClose !== undefined) {
87
87
  onClose();
88
88
  }
89
- onChange({ ...p, label: getPeriodTranslate(periodType) });
89
+ onChange(p);
90
90
  }
91
91
 
92
92
  setIsPeriodPickerShown(false);
@@ -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 && isNotEmpty(value) && (
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: unknown): boolean => {
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
  }
@@ -37,7 +37,6 @@ export interface IDatePeriod {
37
37
 
38
38
  export interface IPeriod extends IDatePeriod {
39
39
  periodType: string;
40
- label?: string;
41
40
  }
42
41
 
43
42
  export type IPeriodGetter = () => IDatePeriod;