@true-engineering/true-react-common-ui-kit 4.0.0-alpha26 → 4.0.0-alpha28

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-alpha26",
3
+ "version": "4.0.0-alpha28",
4
4
  "description": "True Engineering React UI Kit with theming support",
5
5
  "author": "True Engineering (https://trueengineering.ru)",
6
6
  "keywords": [
@@ -1,6 +1,10 @@
1
1
  import { useMemo } from 'react';
2
- import { addDataTestId, getTestId } from '@true-engineering/true-react-platform-helpers';
3
- import { addDataAttributes } from '../../helpers';
2
+ import {
3
+ addDataAttributes,
4
+ addDataTestId,
5
+ getTestId,
6
+ isNotEmpty,
7
+ } from '@true-engineering/true-react-platform-helpers';
4
8
  import { useTweakStyles } from '../../hooks';
5
9
  import { ICommonProps } from '../../types';
6
10
  import { Button } from '../Button';
@@ -70,7 +74,7 @@ export function FiltersPane<Values extends Record<string, unknown>, Content = Va
70
74
  const filtersKeys = enabledFilters ?? Object.keys(filtersConfig);
71
75
 
72
76
  const handleClear = () => {
73
- if (onClear !== undefined) {
77
+ if (isNotEmpty(onClear)) {
74
78
  onClear();
75
79
  return;
76
80
  }
@@ -82,8 +86,7 @@ export function FiltersPane<Values extends Record<string, unknown>, Content = Va
82
86
 
83
87
  const shouldShowClearButton =
84
88
  hasClearButton &&
85
- (search !== undefined ||
86
- filtersKeys.filter((key) => filtersConfig[key] !== undefined).length > 0);
89
+ (isNotEmpty(search) || filtersKeys.some((key) => isNotEmpty(filtersConfig[key])));
87
90
 
88
91
  const clearButton = (
89
92
  <div className={classes.clear}>
@@ -101,7 +104,7 @@ export function FiltersPane<Values extends Record<string, unknown>, Content = Va
101
104
  );
102
105
 
103
106
  return (
104
- <div className={classes.root} {...addDataTestId(testId)} {...addDataAttributes(data)}>
107
+ <div className={classes.root} {...addDataAttributes(data, testId)}>
105
108
  {/* Settings */}
106
109
  {onSettingsButtonClick !== undefined && (
107
110
  <div
@@ -1,4 +1,5 @@
1
1
  import { useMemo } from 'react';
2
+ import { getTestId } from '@true-engineering/true-react-platform-helpers';
2
3
  import { getLocale } from '../../helpers';
3
4
  import { FilterInterval } from '../FilterInterval';
4
5
  import { FilterMultiSelect } from '../FilterMultiSelect';
@@ -32,7 +33,7 @@ export function Filter<Values extends Record<string, unknown>, Key extends keyof
32
33
  onClose={onClose}
33
34
  localeKey={translatesLocaleKey}
34
35
  locale={translates}
35
- testId={testId !== undefined ? `${testId}-select` : undefined}
36
+ testId={getTestId(testId, 'select')}
36
37
  {...filter}
37
38
  />
38
39
  );
@@ -48,7 +49,7 @@ export function Filter<Values extends Record<string, unknown>, Key extends keyof
48
49
  onClose={onClose}
49
50
  localeKey={translatesLocaleKey}
50
51
  locale={translates}
51
- testId={testId !== undefined ? `${testId}-period` : undefined}
52
+ testId={getTestId(testId, 'period')}
52
53
  {...filter}
53
54
  />
54
55
  );
@@ -64,14 +65,14 @@ export function Filter<Values extends Record<string, unknown>, Key extends keyof
64
65
  onEndBtnSubmit={() => onChange(undefined)}
65
66
  localeKey={translatesLocaleKey}
66
67
  locale={translates}
67
- testId={testId !== undefined ? `${testId}-dates` : undefined}
68
+ testId={getTestId(testId, 'dates')}
68
69
  {...filter}
69
70
  />
70
71
  );
71
72
  }
72
73
 
73
74
  if (filter.type === 'multiSelect') {
74
- const preparedValue = isMultiSelectValue<any>(value) ? value : undefined;
75
+ const preparedValue = isMultiSelectValue<any>(value) ? value : undefined; // eslint-disable-line @typescript-eslint/no-explicit-any
75
76
 
76
77
  return (
77
78
  <FilterMultiSelect
@@ -80,7 +81,7 @@ export function Filter<Values extends Record<string, unknown>, Key extends keyof
80
81
  onClose={onClose}
81
82
  localeKey={translatesLocaleKey}
82
83
  locale={translates}
83
- testId={testId !== undefined ? `${testId}-multiSelect` : undefined}
84
+ testId={getTestId(testId, 'multiSelect')}
84
85
  {...filter}
85
86
  />
86
87
  );
@@ -96,26 +97,24 @@ export function Filter<Values extends Record<string, unknown>, Key extends keyof
96
97
  localeKey={translatesLocaleKey}
97
98
  locale={translates}
98
99
  labelName={filter.name}
99
- testId={testId !== undefined ? `${testId}-interval` : undefined}
100
+ testId={getTestId(testId, 'interval')}
100
101
  {...filter}
101
102
  />
102
103
  );
103
104
  }
104
105
 
105
- if (filter.type === 'boolean') {
106
- return null;
107
- }
108
-
109
106
  if (filter.type === 'custom' && filter.component) {
110
107
  const Component = filter.component;
111
108
 
112
- return <Component {...props} filter={filter} />;
109
+ return <Component {...props} filter={filter} testId={getTestId(testId, 'dropdown')} />;
113
110
  }
114
111
 
115
- console.warn(
116
- `%cДля фильтра ${filter.name} не задан тип или component`,
117
- 'background: red; color: black',
118
- );
112
+ if (filter.type !== 'boolean') {
113
+ console.warn(
114
+ `%cДля фильтра ${filter.name} не задан тип или component`,
115
+ 'background: red; color: black',
116
+ );
117
+ }
119
118
 
120
119
  return null;
121
120
  }
@@ -1,8 +1,14 @@
1
1
  import { ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
2
  import clsx from 'clsx';
3
3
  import { debounce } from 'ts-debounce';
4
- import { isReactNodeNotEmpty } from '@true-engineering/true-react-platform-helpers';
5
- import { addDataAttributes } from '../../../../helpers';
4
+ import {
5
+ addDataTestId,
6
+ getTestId,
7
+ isReactNodeNotEmpty,
8
+ addDataAttributes,
9
+ isArrayNotEmpty,
10
+ isNotEmpty,
11
+ } from '@true-engineering/true-react-platform-helpers';
6
12
  import { useIsMounted, useTweakStyles } from '../../../../hooks';
7
13
  import { ICommonProps } from '../../../../types';
8
14
  import { Button } from '../../../Button';
@@ -227,7 +233,7 @@ export function FilterSelect<Value>({
227
233
  }, []);
228
234
 
229
235
  return (
230
- <div className={classes.root} {...addDataAttributes(data)}>
236
+ <div className={classes.root} {...addDataAttributes(data, testId)}>
231
237
  {isSearchEnabled && (
232
238
  <div className={classes.dropdownInput}>
233
239
  <SearchInput
@@ -235,7 +241,7 @@ export function FilterSelect<Value>({
235
241
  placeholder={translates.searchPlaceholder}
236
242
  onChange={handleOnChange}
237
243
  tweakStyles={tweakSearchInputStyles}
238
- testId={testId !== undefined ? `${testId}-search` : undefined}
244
+ testId={getTestId(testId, 'search')}
239
245
  shouldFocusOnMount
240
246
  />
241
247
  </div>
@@ -243,19 +249,17 @@ export function FilterSelect<Value>({
243
249
 
244
250
  {!isLoading && (
245
251
  <>
246
- {allOptions.length !== 0 && (
252
+ {isArrayNotEmpty(allOptions) && (
247
253
  <div
248
- className={clsx(classes.list, hasClearButton && classes.withClearButton)}
249
- data-testid={testId !== undefined ? `${testId}-list` : undefined}
254
+ className={clsx(classes.list, { [classes.withClearButton]: hasClearButton })}
255
+ {...addDataTestId(testId, 'list')}
250
256
  >
251
- {isGroupingEnabled && value !== undefined && (
257
+ {isGroupingEnabled && isNotEmpty(value) && (
252
258
  <>
253
259
  <div
254
- className={clsx(
255
- classes.label,
256
- classes.labelChosen,
257
- !isSearchEnabled && classes.withoutTopGap,
258
- )}
260
+ className={clsx(classes.label, classes.labelChosen, {
261
+ [classes.withoutTopGap]: !isSearchEnabled,
262
+ })}
259
263
  >
260
264
  {translates.chosen}
261
265
  </div>
@@ -269,7 +273,7 @@ export function FilterSelect<Value>({
269
273
  </>
270
274
  )}
271
275
  {allOptions.map((item, index) => {
272
- const isActive = value !== undefined && getValueId(value) === getValueId(item);
276
+ const isActive = isNotEmpty(value) && getValueId(value) === getValueId(item);
273
277
  if (isGroupingEnabled && isActive) {
274
278
  return null;
275
279
  }
@@ -287,8 +291,7 @@ export function FilterSelect<Value>({
287
291
  }
288
292
  onClick={() => handleChange(item)}
289
293
  >
290
- {/* data нужно ли? */}
291
- <div className={classes.option} data-option={id}>
294
+ <div className={classes.option} {...addDataAttributes({ id, option: id })}>
292
295
  {view}
293
296
  </div>
294
297
  {isActive && (
@@ -320,17 +323,13 @@ export function FilterSelect<Value>({
320
323
  )}
321
324
 
322
325
  {/* Nothing found */}
323
- {allOptions.length === 0 && (
326
+ {!isArrayNotEmpty(allOptions) && (
324
327
  <div className={classes.nothingFound}>{translates.nothingFound}</div>
325
328
  )}
326
329
 
327
330
  {/* Controls and footer */}
328
331
  {(hasClearButton || hasFooter) && (
329
- <div
330
- className={clsx(classes.panel, {
331
- [classes.panelWithFooter]: hasFooter,
332
- })}
333
- >
332
+ <div className={clsx(classes.panel, { [classes.panelWithFooter]: hasFooter })}>
334
333
  {hasFooter && <div className={classes.footer}>{footer}</div>}
335
334
 
336
335
  {hasClearButton && (
@@ -339,7 +338,7 @@ export function FilterSelect<Value>({
339
338
  onClick={handleClear}
340
339
  size="s"
341
340
  view="text"
342
- testId={testId !== undefined ? `${testId}-clear-button` : undefined}
341
+ testId={getTestId(testId, 'clear-button')}
343
342
  tweakStyles={tweakClearButtonStyles}
344
343
  >
345
344
  {translates.clear}
@@ -1,4 +1,5 @@
1
1
  import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
+ import { getTestId } from '@true-engineering/true-react-platform-helpers';
2
3
  import { useOnClickOutside, useTweakStyles } from '../../../../hooks';
3
4
  import { ICommonProps } from '../../../../types';
4
5
  import { PERIODS, PERIODS_GETTERS } from '../../constants';
@@ -146,7 +147,7 @@ export const FilterWithPeriod: FC<IFilterWithPeriodProps> = ({
146
147
  locale={translates}
147
148
  tweakStyles={tweakSelectStyles}
148
149
  getValueView={getPeriodTranslate}
149
- testId={testId !== undefined ? `${testId}-select` : undefined}
150
+ testId={getTestId(testId, 'select')}
150
151
  />
151
152
  </div>
152
153
  )}
@@ -168,7 +169,7 @@ export const FilterWithPeriod: FC<IFilterWithPeriodProps> = ({
168
169
  onChange={handleCustomDateChange}
169
170
  localeKey={localeKey}
170
171
  locale={translates}
171
- testId={testId !== undefined ? `${testId}-dates` : undefined}
172
+ testId={getTestId(testId, 'dates')}
172
173
  />
173
174
  </div>
174
175
  )}
@@ -1,7 +1,10 @@
1
1
  import { MouseEventHandler } from 'react';
2
2
  import clsx from 'clsx';
3
- import { addDataTestId, getTestId } from '@true-engineering/true-react-platform-helpers';
4
- import { addDataAttributes } from '../../../../helpers';
3
+ import {
4
+ addDataAttributes,
5
+ getTestId,
6
+ isNotEmpty,
7
+ } from '@true-engineering/true-react-platform-helpers';
5
8
  import { useTweakStyles } from '../../../../hooks';
6
9
  import { ICommonProps } from '../../../../types';
7
10
  import { Icon } from '../../../Icon';
@@ -93,8 +96,7 @@ export function FilterWrapper<Values extends Record<string, unknown>, Key extend
93
96
  [classes.boolean]: isBoolean,
94
97
  [classes.disabled]: isDisabled,
95
98
  })}
96
- {...addDataTestId(testId)}
97
- {...addDataAttributes(data)}
99
+ {...addDataAttributes(data, testId)}
98
100
  {...referenceProps}
99
101
  >
100
102
  <div
@@ -102,7 +104,7 @@ export function FilterWrapper<Values extends Record<string, unknown>, Key extend
102
104
  className={clsx(classes.item, { [classes.booleanItem]: isBoolean })}
103
105
  >
104
106
  <div className={classes.name}>{filter.name}</div>
105
- {!isBoolean && value !== undefined && value !== null && (
107
+ {!isBoolean && isNotEmpty(value) && (
106
108
  <div className={classes.value}>
107
109
  <FilterValueView
108
110
  value={value}
@@ -1,6 +1,11 @@
1
1
  import { ReactNode, useMemo, useRef, useState } from 'react';
2
2
  import clsx from 'clsx';
3
- import { addDataAttributes } from '../../../../helpers';
3
+ import {
4
+ addDataAttributes,
5
+ addDataTestId,
6
+ getTestId,
7
+ isNotEmpty,
8
+ } from '@true-engineering/true-react-platform-helpers';
4
9
  import { useOnClickOutside, useTweakStyles } from '../../../../hooks';
5
10
  import { ICommonProps } from '../../../../types';
6
11
  import { Icon } from '../../../Icon';
@@ -89,11 +94,6 @@ export function FiltersPaneSearch<Value>({
89
94
  setIsOpen(false);
90
95
  };
91
96
 
92
- const selectedFieldLabel = useMemo(
93
- () => (field !== undefined && getValueView !== undefined ? getValueView(field) : undefined),
94
- [field],
95
- );
96
-
97
97
  return (
98
98
  <div
99
99
  className={clsx(classes.root, {
@@ -101,8 +101,7 @@ export function FiltersPaneSearch<Value>({
101
101
  [classes.disabled]: isDisabled,
102
102
  })}
103
103
  ref={refRoot}
104
- data-testid={testId}
105
- {...addDataAttributes(data)}
104
+ {...addDataAttributes(data, testId)}
106
105
  >
107
106
  <SearchInput
108
107
  value={value}
@@ -111,7 +110,7 @@ export function FiltersPaneSearch<Value>({
111
110
  tweakStyles={tweakSearchInputStyles}
112
111
  onFocus={() => setIsInputFocused(true)}
113
112
  onBlur={() => setIsInputFocused(false)}
114
- testId={testId !== undefined ? `${testId}-input` : undefined}
113
+ testId={getTestId(testId, 'input')}
115
114
  maxLength={maxLength}
116
115
  isDisabled={isDisabled}
117
116
  />
@@ -122,15 +121,10 @@ export function FiltersPaneSearch<Value>({
122
121
  <div
123
122
  className={classes.selectBlock}
124
123
  onClick={!isDisabled ? () => setIsOpen(!isOpen) : undefined}
125
- data-testid={testId !== undefined ? `${testId}-select` : undefined}
124
+ {...addDataTestId(testId, 'select')}
126
125
  >
127
- <div
128
- className={clsx(
129
- classes.selectLabel,
130
- selectedFieldLabel !== undefined && classes.active,
131
- )}
132
- >
133
- {selectedFieldLabel ?? translates.displayedFields}
126
+ <div className={clsx(classes.selectLabel, { [classes.active]: isNotEmpty(field) })}>
127
+ {isNotEmpty(field) ? getValueView?.(field) : translates.displayedFields}
134
128
  </div>
135
129
  <div className={clsx(classes.chevronIcon, isOpen && classes.open)}>
136
130
  <Icon type="chevron-down" />
@@ -152,7 +146,7 @@ export function FiltersPaneSearch<Value>({
152
146
  onChange={handleFieldsChange}
153
147
  isSearchEnabled={isSelectSearchEnabled}
154
148
  hasClearButton={hasClearSelectButton}
155
- testId={testId !== undefined ? `${testId}-dropdown` : undefined}
149
+ testId={getTestId(testId, 'dropdown')}
156
150
  />
157
151
  </div>
158
152
  )}
@@ -1,4 +1,5 @@
1
1
  import { FC, ReactNode } from 'react';
2
+ import { ITestIdProps } from '../../types';
2
3
  import { IDatePickerProps } from '../DatePicker';
3
4
  import { IMultiSelectListValues } from '../MultiSelectList';
4
5
  import type {
@@ -84,7 +85,7 @@ export type IDateRangeConfigItem<Value> = IConfigItemBasicBase<Value> & {
84
85
  dateFormat?: string;
85
86
  } & Omit<IFilterWithPeriodProps, 'value' | 'onChange' | 'setIsOpen'>;
86
87
 
87
- export interface ICustomComponentProps<Value> {
88
+ export interface ICustomComponentProps<Value> extends ITestIdProps {
88
89
  value?: Value;
89
90
  onChange: (v?: Value) => void;
90
91
  onClose?: () => void;
@@ -119,8 +119,9 @@ export function SelectList<Value>({
119
119
  )}
120
120
  {listOptions.map((opt, i) => {
121
121
  const optionValue = options[i];
122
+ const id = convertValueToId(optionValue);
122
123
  const isFocused = focusedIndex === i;
123
- const isActive = activeOptionsIds.has(convertValueToId(optionValue));
124
+ const isActive = activeOptionsIds.has(id);
124
125
  // проверяем, что опция задизейблена
125
126
  const isDisabled = optionsDisableMap[i];
126
127
 
@@ -135,6 +136,7 @@ export function SelectList<Value>({
135
136
  isMultiSelect={isMultiSelect}
136
137
  onOptionSelect={onOptionSelect}
137
138
  onToggleCheckbox={onToggleCheckbox}
139
+ data={{ id }}
138
140
  >
139
141
  {opt}
140
142
  </SelectListItem>
@@ -7,12 +7,13 @@ import {
7
7
  } from 'react';
8
8
  import clsx from 'clsx';
9
9
  import { type Classes } from 'jss';
10
- import { addDataAttributes } from '../../../../helpers';
10
+ import { addDataAttributes } from '@true-engineering/true-react-platform-helpers';
11
+ import { IDataAttributesProps } from '../../../../types';
11
12
  import { Checkbox } from '../../../Checkbox';
12
13
  import { ScrollIntoViewIfNeeded } from '../../../ScrollIntoViewIfNeeded';
13
14
  import { checkboxStyles } from './SelectListItem.styles';
14
15
 
15
- export interface ISelectListItemProps {
16
+ export interface ISelectListItemProps extends IDataAttributesProps {
16
17
  index: number;
17
18
  isSemiChecked?: boolean;
18
19
  isDisabled?: boolean;
@@ -38,6 +39,7 @@ export const SelectListItem: FC<ISelectListItemProps> = ({
38
39
  children,
39
40
  isFocused,
40
41
  isMultiSelect,
42
+ data,
41
43
  onOptionSelect,
42
44
  onToggleCheckbox,
43
45
  }) => {
@@ -67,6 +69,7 @@ export const SelectListItem: FC<ISelectListItemProps> = ({
67
69
  disabled: isDisabled,
68
70
  active: isActive,
69
71
  focused: isFocused,
72
+ ...data,
70
73
  })}
71
74
  onClick={!isDisabled && !isMultiSelect ? (event) => onOptionSelect(index, event) : undefined}
72
75
  >