@true-engineering/true-react-common-ui-kit 3.15.4 → 3.16.0

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.
Files changed (25) hide show
  1. package/README.md +10 -0
  2. package/dist/components/FiltersPane/FiltersPane.styles.d.ts +2 -0
  3. package/dist/components/FiltersPane/components/Filter/Filter.d.ts +2 -7
  4. package/dist/components/FiltersPane/components/FilterSelect/FilterSelect.d.ts +2 -1
  5. package/dist/components/FiltersPane/components/FilterWrapper/FilterWrapper.d.ts +2 -3
  6. package/dist/components/FiltersPane/components/FilterWrapper/FilterWrapper.styles.d.ts +1 -1
  7. package/dist/components/FiltersPane/components/FilterWrapper/helpers.d.ts +1 -0
  8. package/dist/components/NewMoreMenu/NewMoreMenu.d.ts +1 -3
  9. package/dist/components/WithPopup/WithPopup.d.ts +5 -4
  10. package/dist/components/WithPopup/types.d.ts +3 -1
  11. package/dist/true-react-common-ui-kit.js +1077 -1233
  12. package/dist/true-react-common-ui-kit.js.map +1 -1
  13. package/dist/true-react-common-ui-kit.umd.cjs +1076 -1232
  14. package/dist/true-react-common-ui-kit.umd.cjs.map +1 -1
  15. package/package.json +1 -1
  16. package/src/components/FiltersPane/FiltersPane.styles.ts +5 -1
  17. package/src/components/FiltersPane/FiltersPane.tsx +9 -5
  18. package/src/components/FiltersPane/components/Filter/Filter.tsx +53 -142
  19. package/src/components/FiltersPane/components/FilterSelect/FilterSelect.tsx +10 -3
  20. package/src/components/FiltersPane/components/FilterWrapper/FilterWrapper.styles.ts +6 -16
  21. package/src/components/FiltersPane/components/FilterWrapper/FilterWrapper.tsx +72 -114
  22. package/src/components/FiltersPane/components/FilterWrapper/helpers.ts +14 -0
  23. package/src/components/NewMoreMenu/NewMoreMenu.tsx +8 -13
  24. package/src/components/WithPopup/WithPopup.tsx +16 -22
  25. package/src/components/WithPopup/types.ts +4 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@true-engineering/true-react-common-ui-kit",
3
- "version": "3.15.4",
3
+ "version": "3.16.0",
4
4
  "description": "True Engineering React UI Kit with theming support",
5
5
  "author": "True Engineering (https://trueengineering.ru)",
6
6
  "keywords": [
@@ -1,5 +1,6 @@
1
1
  import { colors, ITweakStyles, createThemedStyles, animations } from '../../theme';
2
2
  import { IButtonStyles } from '../Button';
3
+ import type { IFilterWrapperStyles } from './components';
3
4
 
4
5
  export const FILTER_HEIGHT = 36;
5
6
 
@@ -84,5 +85,8 @@ export const innerTextButtonStyles: IButtonStyles = {
84
85
 
85
86
  export type IFiltersPaneStyles = ITweakStyles<
86
87
  typeof useStyles,
87
- { tweakClearButton: IButtonStyles }
88
+ {
89
+ tweakClearButton: IButtonStyles;
90
+ tweakFilterWrapper: IFilterWrapperStyles;
91
+ }
88
92
  >;
@@ -1,4 +1,4 @@
1
- import { useMemo, useRef } from 'react';
1
+ import { useMemo } from 'react';
2
2
  import { addDataTestId, getTestId } from '@true-engineering/true-react-platform-helpers';
3
3
  import { addDataAttributes } from '../../helpers';
4
4
  import { useTweakStyles } from '../../hooks';
@@ -53,9 +53,13 @@ export function FiltersPane<Values extends Record<string, unknown>, Content = Va
53
53
  currentComponentName: 'FiltersPane',
54
54
  });
55
55
 
56
- const translates = useMemo(() => getLocale(localeKey, locale), [localeKey, locale]);
56
+ const tweakFilterWrapperStyles = useTweakStyles({
57
+ tweakStyles,
58
+ className: 'tweakFilterWrapper',
59
+ currentComponentName: 'FiltersPane',
60
+ });
57
61
 
58
- const ref = useRef<HTMLDivElement>(null);
62
+ const translates = useMemo(() => getLocale(localeKey, locale), [localeKey, locale]);
59
63
 
60
64
  const filtersKeys = enabledFilters || Object.keys(filtersConfig);
61
65
 
@@ -91,7 +95,7 @@ export function FiltersPane<Values extends Record<string, unknown>, Content = Va
91
95
  );
92
96
 
93
97
  return (
94
- <div className={classes.root} ref={ref} {...addDataTestId(testId)} {...addDataAttributes(data)}>
98
+ <div className={classes.root} {...addDataTestId(testId)} {...addDataAttributes(data)}>
95
99
  {/* Settings */}
96
100
  {onSettingsButtonClick !== undefined && (
97
101
  <div
@@ -137,7 +141,7 @@ export function FiltersPane<Values extends Record<string, unknown>, Content = Va
137
141
  value={currentValue}
138
142
  key={key as string}
139
143
  isDisabled={isDisabled || filter?.requiredFilledFilters?.some((item) => !values[item])}
140
- filtersPaneRef={ref}
144
+ tweakStyles={tweakFilterWrapperStyles}
141
145
  testId={getTestId(testId, `filter-${String(key)}`)}
142
146
  />
143
147
  );
@@ -1,7 +1,4 @@
1
- import { useState, useRef, useMemo, useLayoutEffect, RefObject } from 'react';
2
- import clsx from 'clsx';
3
- import { Classes } from 'jss';
4
- import { useOnClickOutsideWithRef } from '../../../../hooks';
1
+ import { useMemo } from 'react';
5
2
  import { getLocale } from '../../helpers';
6
3
  import { IFilterMultiSelectValues, IFilterWithDatesValue, IPeriod } from '../../types';
7
4
  import { FilterInterval } from '../FilterInterval';
@@ -13,146 +10,55 @@ import type { IFilterWrapperProps } from '../FilterWrapper';
13
10
 
14
11
  export interface IFilterProps<Values, Key extends keyof Values>
15
12
  extends IFilterWrapperProps<Values, Key> {
16
- parentRef?: RefObject<HTMLElement>;
17
- isInline?: boolean;
18
- filtersPaneRef: RefObject<HTMLDivElement> | null;
19
- classes: Classes<'left' | 'right' | 'dropdown'>;
20
13
  onChange: <V>(v: V) => void;
21
14
  onClose?: () => void;
22
15
  }
23
16
 
24
- export function Filter<Values, Key extends keyof Values>({
25
- filter,
26
- value,
27
- parentRef,
28
- isInline,
29
- onChange,
30
- onClose,
31
- localeKey,
32
- locale,
33
- filtersPaneRef,
34
- testId,
35
- classes,
36
- }: IFilterProps<Values, Key>): JSX.Element | null {
37
- const ref = useRef<HTMLDivElement>(null);
38
- const [dropdownPosition, setDropdownPosition] = useState<'left' | 'right'>('left');
17
+ export function Filter<Values, Key extends keyof Values>(
18
+ props: IFilterProps<Values, Key>,
19
+ ): JSX.Element | null {
20
+ const { filter, value, onChange, onClose, localeKey, locale, testId } = props;
39
21
  const translatesLocaleKey = filter.localeKey ?? localeKey;
40
22
  const translates = useMemo(
41
23
  () => getLocale(translatesLocaleKey, locale, filter.locale),
42
24
  [translatesLocaleKey, locale, filter.locale],
43
25
  );
44
26
 
45
- useOnClickOutsideWithRef(
46
- ref,
47
- () => {
48
- if (!isInline && onClose !== undefined) {
49
- onClose();
50
- }
51
- },
52
- parentRef,
53
- );
54
-
55
- useLayoutEffect(() => {
56
- if (
57
- ref.current === null ||
58
- filtersPaneRef === undefined ||
59
- filtersPaneRef === null ||
60
- filtersPaneRef?.current === null
61
- ) {
62
- return;
63
- }
64
-
65
- const { width, left } = ref.current.getBoundingClientRect();
66
- const filtersPaneWidth = filtersPaneRef.current.offsetWidth;
67
-
68
- const filterValueWidth = ref.current.parentElement
69
- ? ref.current.parentElement.getBoundingClientRect().width
70
- : 0;
71
-
72
- if (filtersPaneWidth - left < width - filterValueWidth) {
73
- setDropdownPosition('right');
74
- } else if (left < 0) {
75
- setDropdownPosition('left');
76
- }
77
- }, [value, filtersPaneRef]);
78
-
79
- const props = {
80
- ref,
81
- className: clsx(classes[dropdownPosition], {
82
- [classes.dropdown]: !isInline,
83
- }),
84
- };
85
-
86
- const handleOnClose = () => {
87
- if (onClose !== undefined) {
88
- onClose();
89
- }
90
- };
91
-
92
- if (filter.type === 'custom' && filter.component) {
93
- const Component = filter.component;
94
- return (
95
- <div {...props}>
96
- <Component
97
- {...{
98
- value,
99
- onChange,
100
- onClose,
101
- filter,
102
- locale,
103
- localeKey,
104
- testId,
105
- }}
106
- />
107
- </div>
108
- );
109
- } else if (filter.type === 'custom' && filter.component === undefined) {
110
- console.warn(
111
- `%cДля фильтра типа custom (${filter.name}) в конфиге обязательно нужно задать component`,
112
- 'background: red; color: black',
113
- );
114
- }
115
-
116
27
  if (filter.type === 'select') {
117
28
  return (
118
- <div {...props}>
119
- <FilterSelect
120
- onChange={onChange}
121
- value={value}
122
- localeKey={translatesLocaleKey}
123
- locale={translates}
124
- testId={testId !== undefined ? `${testId}-select` : undefined}
125
- {...filter}
126
- />
127
- </div>
29
+ <FilterSelect
30
+ value={value}
31
+ onChange={onChange}
32
+ onClose={onClose}
33
+ localeKey={translatesLocaleKey}
34
+ locale={translates}
35
+ testId={testId !== undefined ? `${testId}-select` : undefined}
36
+ {...filter}
37
+ />
128
38
  );
129
39
  }
130
40
 
131
41
  if (filter.type === 'dateRange') {
132
42
  return (
133
- <div {...props}>
134
- <FilterWithPeriod
135
- localeKey={translatesLocaleKey}
136
- locale={translates}
137
- onChange={onChange}
138
- value={{ ...value } as IPeriod}
139
- onClose={handleOnClose}
140
- testId={testId !== undefined ? `${testId}-period` : undefined}
141
- {...filter}
142
- />
143
- </div>
43
+ <FilterWithPeriod
44
+ value={{ ...value } as IPeriod}
45
+ onChange={onChange}
46
+ onClose={onClose}
47
+ localeKey={translatesLocaleKey}
48
+ locale={translates}
49
+ testId={testId !== undefined ? `${testId}-period` : undefined}
50
+ {...filter}
51
+ />
144
52
  );
145
53
  }
146
54
 
147
55
  if (filter.type === 'dateRangeWithoutPeriod') {
148
- const dateRangeValue = value as unknown as IFilterWithDatesValue;
149
-
150
56
  return (
151
- <div {...props} style={{ width: 320 }}>
57
+ <div style={{ width: 320 }}>
152
58
  <FilterWithDates
153
- value={dateRangeValue}
154
- onEndBtnSubmit={() => onChange(undefined)}
59
+ value={value as unknown as IFilterWithDatesValue}
155
60
  onChange={(v) => onChange({ ...v, periodType: 'CUSTOM' })}
61
+ onEndBtnSubmit={() => onChange(undefined)}
156
62
  localeKey={translatesLocaleKey}
157
63
  locale={translates}
158
64
  testId={testId !== undefined ? `${testId}-dates` : undefined}
@@ -164,36 +70,41 @@ export function Filter<Values, Key extends keyof Values>({
164
70
 
165
71
  if (filter.type === 'multiSelect') {
166
72
  return (
167
- <div {...props}>
168
- <FilterMultiSelect
169
- onChange={onChange}
170
- onClose={handleOnClose}
171
- value={value as unknown as IFilterMultiSelectValues<any>}
172
- localeKey={translatesLocaleKey}
173
- locale={translates}
174
- testId={testId !== undefined ? `${testId}-multiSelect` : undefined}
175
- {...filter}
176
- />
177
- </div>
73
+ <FilterMultiSelect
74
+ value={value as unknown as IFilterMultiSelectValues<any>}
75
+ onChange={onChange}
76
+ onClose={onClose}
77
+ localeKey={translatesLocaleKey}
78
+ locale={translates}
79
+ testId={testId !== undefined ? `${testId}-multiSelect` : undefined}
80
+ {...filter}
81
+ />
178
82
  );
179
83
  }
180
84
 
181
85
  if (filter.type === 'interval') {
182
86
  return (
183
- <div {...props}>
184
- <FilterInterval
185
- value={value as unknown as number[]}
186
- labelName={filter.name}
187
- localeKey={translatesLocaleKey}
188
- locale={translates}
189
- onChange={onChange}
190
- testId={testId !== undefined ? `${testId}-interval` : undefined}
191
- {...filter}
192
- />
193
- </div>
87
+ <FilterInterval
88
+ value={value as unknown as number[]}
89
+ onChange={onChange}
90
+ localeKey={translatesLocaleKey}
91
+ locale={translates}
92
+ labelName={filter.name}
93
+ testId={testId !== undefined ? `${testId}-interval` : undefined}
94
+ {...filter}
95
+ />
194
96
  );
195
97
  }
196
98
 
99
+ if (filter.type === 'boolean') {
100
+ return null;
101
+ }
102
+
103
+ if (filter.type === 'custom' && filter.component) {
104
+ const Component = filter.component;
105
+ return <Component {...props} filter={filter} />;
106
+ }
107
+
197
108
  console.warn(
198
109
  `%cДля фильтра ${filter.name} не задан тип или component`,
199
110
  'background: red; color: black',
@@ -22,6 +22,7 @@ import {
22
22
  export interface IFilterSelectProps<Value> extends ICommonProps<IFilterSelectStyles> {
23
23
  value?: Value;
24
24
  onChange: (value?: Value) => void;
25
+ onClose?: () => void;
25
26
  /**
26
27
  * @default false
27
28
  */
@@ -53,6 +54,7 @@ export function FilterSelect<Value>({
53
54
  localeKey,
54
55
  locale,
55
56
  onChange,
57
+ onClose,
56
58
  options,
57
59
  fetchOptions,
58
60
  footer,
@@ -137,11 +139,16 @@ export function FilterSelect<Value>({
137
139
  }
138
140
  };
139
141
 
142
+ const handleChange = (val?: Value) => {
143
+ onChange(val);
144
+ onClose?.();
145
+ };
146
+
140
147
  const handleClear = () => {
141
148
  if (options !== undefined) {
142
149
  setAllOptions(options);
143
150
  }
144
- onChange(undefined);
151
+ handleChange(undefined);
145
152
  setSearchValue('');
146
153
  };
147
154
 
@@ -252,7 +259,7 @@ export function FilterSelect<Value>({
252
259
  >
253
260
  {translates.chosen}
254
261
  </div>
255
- <div className={classes.item} onClick={() => onChange(undefined)}>
262
+ <div className={classes.item} onClick={() => handleChange(undefined)}>
256
263
  <div className={classes.option}>{getValueView(value)}</div>
257
264
  <div className={classes.icon}>
258
265
  <Icon type="check" />
@@ -278,7 +285,7 @@ export function FilterSelect<Value>({
278
285
  ? initIntersectionObserver
279
286
  : undefined
280
287
  }
281
- onClick={() => onChange(item)}
288
+ onClick={() => handleChange(item)}
282
289
  >
283
290
  {/* data нужно ли? */}
284
291
  <div className={classes.option} data-option={id}>
@@ -87,24 +87,14 @@ export const useStyles = createThemedStyles('FilterWrapper', {
87
87
  minWidth: 0,
88
88
  },
89
89
 
90
- animationEnd: {
91
- opacity: 0,
92
- transform: 'translateY(15px)',
93
- transition: '0.15s ease-in-out',
94
- transitionProperty: 'opacity, transform',
95
- },
90
+ animationEnd: animations.slideUp['slide-up-exit'],
96
91
 
97
- animationStart: {
98
- opacity: 1,
99
- transform: 'translateY(0)',
100
- transition: '0.15s ease-in-out',
101
- transitionProperty: 'opacity, transform',
102
- },
92
+ animationStart: animations.slideUp['slide-up-enter-active'],
103
93
 
104
- 'dropdown-enter': { extend: 'animationEnd' },
105
- 'dropdown-enter-active': { extend: 'animationStart' },
106
- 'dropdown-exit-active': { extend: 'animationStart' },
107
- 'dropdown-exit': { extend: 'animationEnd' },
94
+ 'dropdown-initial': { extend: 'animationEnd' },
95
+ 'dropdown-open': { extend: 'animationStart' },
96
+ 'dropdown-close': { extend: 'animationEnd' },
97
+ 'dropdown-unmounted': { extend: 'animationEnd' },
108
98
  });
109
99
 
110
100
  export type IFilterWrapperStyles = ITweakStyles<
@@ -1,14 +1,14 @@
1
- import { useState, useRef, RefObject } from 'react';
2
- import { CSSTransition } from 'react-transition-group';
3
1
  import clsx from 'clsx';
4
2
  import { addDataTestId, getTestId } from '@true-engineering/true-react-platform-helpers';
5
3
  import { addDataAttributes } from '../../../../helpers';
6
4
  import { useTweakStyles } from '../../../../hooks';
7
5
  import { ICommonProps } from '../../../../types';
8
6
  import { Icon } from '../../../Icon';
7
+ import { WithPopup } from '../../../WithPopup';
9
8
  import { ConfigItem, IFilterLocaleKey, IPartialFilterLocale } from '../../types';
10
9
  import { Filter } from '../Filter';
11
10
  import { FilterValueView } from '../FilterValueView';
11
+ import { isContentNotEmpty } from './helpers';
12
12
  import { useStyles, IFilterWrapperStyles } from './FilterWrapper.styles';
13
13
 
14
14
  export interface IFilterWrapperProps<Values, Key extends keyof Values>
@@ -18,7 +18,6 @@ export interface IFilterWrapperProps<Values, Key extends keyof Values>
18
18
  isDisabled?: boolean;
19
19
  localeKey?: IFilterLocaleKey;
20
20
  locale?: IPartialFilterLocale;
21
- filtersPaneRef: RefObject<HTMLDivElement> | null;
22
21
  onChange: <V>(value: V) => void;
23
22
  }
24
23
 
@@ -30,7 +29,6 @@ export function FilterWrapper<Values, Key extends keyof Values>({
30
29
  localeKey,
31
30
  data,
32
31
  testId,
33
- filtersPaneRef,
34
32
  tweakStyles,
35
33
  onChange,
36
34
  }: IFilterWrapperProps<Values, Key>): JSX.Element {
@@ -42,126 +40,86 @@ export function FilterWrapper<Values, Key extends keyof Values>({
42
40
  currentComponentName: 'FilterWrapper',
43
41
  });
44
42
 
45
- const [isOpen, setIsOpen] = useState(false);
46
- const refItem = useRef<HTMLDivElement>(null);
47
-
48
- const { type } = filter;
49
-
50
- let hasValue = false;
51
-
52
- if (Array.isArray(value) && value.length > 0) {
53
- hasValue = true;
54
- } else if (
55
- typeof value === 'object' &&
56
- Object.values(value as unknown as Record<any, any>).some((v) =>
57
- Array.isArray(v) ? v.length > 0 : Boolean(v),
58
- )
59
- ) {
60
- hasValue = true;
61
- } else if (!Array.isArray(value) && typeof value !== 'object') {
62
- hasValue = Boolean(value);
43
+ if (filter.isInline) {
44
+ return (
45
+ <Filter
46
+ value={value}
47
+ filter={filter}
48
+ localeKey={localeKey}
49
+ locale={locale}
50
+ onChange={onChange}
51
+ testId={testId}
52
+ />
53
+ );
63
54
  }
64
55
 
65
- // Для того, чтобы фильтр закрывался, если мы работаем с простыми значениями, типа селекта
66
- function handleChange<V>(v: V) {
67
- if (type === 'select') {
68
- setIsOpen(false);
69
- }
70
- onChange(v);
71
- }
56
+ const isBoolean = filter.type === 'boolean';
72
57
 
73
58
  const handleLabelClick = () => {
74
- if (!isBoolean && !isDisabled) {
75
- setIsOpen(!isOpen);
76
- }
77
-
78
59
  if (isBoolean) {
79
60
  onChange(!value);
80
61
  }
81
62
  };
82
63
 
83
- const handleOnClose = () => {
84
- setIsOpen(false);
85
- };
86
-
87
- const isBoolean = filter.type === 'boolean';
64
+ const hasValue = isContentNotEmpty(value);
88
65
 
89
- return !filter.isInline ? (
90
- <div
91
- className={clsx(classes.root, {
92
- [classes.noValue]: !hasValue,
93
- [classes.openNoValue]: isOpen && !hasValue,
94
- [classes.withValue]: !isOpen && hasValue,
95
- [classes.openWithValue]: isOpen && hasValue,
96
- [classes.boolean]: isBoolean,
97
- [classes.disabled]: isDisabled,
98
- })}
99
- {...addDataTestId(testId)}
100
- {...addDataAttributes(data)}
101
- >
102
- <div
103
- ref={refItem}
104
- onClick={handleLabelClick}
105
- className={clsx(classes.item, {
106
- [classes.booleanItem]: isBoolean,
107
- })}
108
- >
109
- <div className={classes.name}>{filter.name}</div>
110
- {!isBoolean && value !== undefined && value !== null && (
111
- <div className={classes.value}>
112
- <FilterValueView
113
- value={value}
114
- filter={filter}
115
- localeKey={localeKey}
116
- locale={locale}
117
- testId={getTestId(testId, 'value')}
118
- tweakStyles={tweakFilterValueViewStyles}
119
- />
120
- </div>
121
- )}
122
- {!isBoolean && (
123
- <div className={clsx(classes.iconContainer, isOpen && classes.open)}>
124
- <Icon type="chevron-down" />
66
+ return (
67
+ <WithPopup
68
+ placement="bottom-start"
69
+ canBeFlipped
70
+ isDisabled={isBoolean || isDisabled}
71
+ trigger={({ isActive }) => (
72
+ <div
73
+ className={clsx(classes.root, {
74
+ [classes.noValue]: !hasValue,
75
+ [classes.openNoValue]: isActive && !hasValue,
76
+ [classes.withValue]: !isActive && hasValue,
77
+ [classes.openWithValue]: isActive && hasValue,
78
+ [classes.boolean]: isBoolean,
79
+ [classes.disabled]: isDisabled,
80
+ })}
81
+ {...addDataTestId(testId)}
82
+ {...addDataAttributes(data)}
83
+ >
84
+ <div
85
+ onClick={handleLabelClick}
86
+ className={clsx(classes.item, { [classes.booleanItem]: isBoolean })}
87
+ >
88
+ <div className={classes.name}>{filter.name}</div>
89
+ {!isBoolean && value !== undefined && value !== null && (
90
+ <div className={classes.value}>
91
+ <FilterValueView
92
+ value={value}
93
+ filter={filter}
94
+ localeKey={localeKey}
95
+ locale={locale}
96
+ testId={getTestId(testId, 'value')}
97
+ tweakStyles={tweakFilterValueViewStyles}
98
+ />
99
+ </div>
100
+ )}
101
+ {!isBoolean && (
102
+ <div className={clsx(classes.iconContainer, { [classes.open]: isActive })}>
103
+ <Icon type="chevron-down" />
104
+ </div>
105
+ )}
125
106
  </div>
126
- )}
127
- </div>
128
- <CSSTransition
129
- in={isOpen}
130
- timeout={150}
131
- unmountOnExit
132
- classNames={{
133
- enter: classes['dropdown-enter'],
134
- enterActive: classes['dropdown-enter-active'],
135
- exit: classes['dropdown-exit'],
136
- exitActive: classes['dropdown-exit-active'],
137
- }}
138
- >
139
- <Filter
140
- value={value}
141
- filter={filter}
142
- localeKey={localeKey}
143
- locale={locale}
144
- onClose={handleOnClose}
145
- onChange={handleChange}
146
- parentRef={refItem}
147
- filtersPaneRef={filtersPaneRef}
148
- testId={testId}
149
- classes={classes}
150
- />
151
- </CSSTransition>
152
- </div>
153
- ) : (
154
- <Filter
155
- value={value}
156
- filter={filter}
157
- localeKey={localeKey}
158
- locale={locale}
159
- onClose={handleOnClose}
160
- onChange={onChange}
161
- isInline
162
- filtersPaneRef={filtersPaneRef}
163
- testId={testId}
164
- classes={classes}
165
- />
107
+ </div>
108
+ )}
109
+ >
110
+ {({ onClose, status }) => (
111
+ <div className={classes[`dropdown-${status}`]}>
112
+ <Filter
113
+ value={value}
114
+ filter={filter}
115
+ localeKey={localeKey}
116
+ locale={locale}
117
+ onClose={onClose}
118
+ onChange={onChange}
119
+ testId={testId}
120
+ />
121
+ </div>
122
+ )}
123
+ </WithPopup>
166
124
  );
167
125
  }
@@ -0,0 +1,14 @@
1
+ import { isNotEmpty, isObject } from '@true-engineering/true-react-platform-helpers';
2
+
3
+ export const isContentNotEmpty = (value: unknown): boolean => {
4
+ if (Array.isArray(value)) {
5
+ return value.some(isContentNotEmpty);
6
+ }
7
+ if (isObject(value)) {
8
+ return Object.values(value).some(isContentNotEmpty);
9
+ }
10
+ if (typeof value === 'boolean') {
11
+ return value;
12
+ }
13
+ return isNotEmpty(value);
14
+ };