@snack-uikit/chips 0.24.1 → 0.24.2-preview-08c7f775.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.
- package/README.md +28 -8
- package/dist/cjs/components/ChipChoice/components/ChipChoiceBase/ChipChoiceBase.d.ts +3 -7
- package/dist/cjs/components/ChipChoice/components/ChipChoiceBase/ChipChoiceBase.js +3 -4
- package/dist/cjs/components/ChipChoice/components/ChipChoiceCustom.d.ts +1 -1
- package/dist/cjs/components/ChipChoice/components/ChipChoiceCustom.js +9 -9
- package/dist/cjs/components/ChipChoice/components/ChipChoiceDate.d.ts +1 -1
- package/dist/cjs/components/ChipChoice/components/ChipChoiceDate.js +9 -6
- package/dist/cjs/components/ChipChoice/components/ChipChoiceDateRange.d.ts +1 -1
- package/dist/cjs/components/ChipChoice/components/ChipChoiceDateRange.js +8 -6
- package/dist/cjs/components/ChipChoice/components/ChipChoiceMultiple.d.ts +1 -1
- package/dist/cjs/components/ChipChoice/components/ChipChoiceMultiple.js +8 -10
- package/dist/cjs/components/ChipChoice/components/ChipChoiceSingle.d.ts +1 -1
- package/dist/cjs/components/ChipChoice/components/ChipChoiceSingle.js +9 -9
- package/dist/cjs/components/ChipChoice/components/ChipChoiceTime.d.ts +1 -1
- package/dist/cjs/components/ChipChoice/components/ChipChoiceTime.js +9 -6
- package/dist/cjs/components/ChipChoice/constants.d.ts +1 -0
- package/dist/cjs/components/ChipChoice/constants.js +1 -0
- package/dist/cjs/components/ChipChoice/types.d.ts +7 -3
- package/dist/cjs/components/ChipChoiceRow/ChipChoiceRow.d.ts +12 -6
- package/dist/cjs/components/ChipChoiceRow/ChipChoiceRow.js +123 -24
- package/dist/cjs/components/ChipChoiceRow/components/constants.d.ts +1 -0
- package/dist/cjs/components/ChipChoiceRow/components/constants.js +1 -0
- package/dist/cjs/components/ChipChoiceRow/helpers.d.ts +5 -0
- package/dist/cjs/components/ChipChoiceRow/helpers.js +19 -0
- package/dist/cjs/components/ChipChoiceRow/index.d.ts +1 -0
- package/dist/cjs/components/ChipChoiceRow/index.js +2 -1
- package/dist/cjs/components/ChipChoiceRow/styles.module.css +21 -0
- package/dist/cjs/components/ChipChoiceRow/types.d.ts +5 -5
- package/dist/cjs/constants.d.ts +4 -1
- package/dist/cjs/constants.js +4 -1
- package/dist/esm/components/ChipChoice/components/ChipChoiceBase/ChipChoiceBase.d.ts +3 -7
- package/dist/esm/components/ChipChoice/components/ChipChoiceBase/ChipChoiceBase.js +2 -2
- package/dist/esm/components/ChipChoice/components/ChipChoiceCustom.d.ts +1 -1
- package/dist/esm/components/ChipChoice/components/ChipChoiceCustom.js +6 -9
- package/dist/esm/components/ChipChoice/components/ChipChoiceDate.d.ts +1 -1
- package/dist/esm/components/ChipChoice/components/ChipChoiceDate.js +6 -6
- package/dist/esm/components/ChipChoice/components/ChipChoiceDateRange.d.ts +1 -1
- package/dist/esm/components/ChipChoice/components/ChipChoiceDateRange.js +5 -6
- package/dist/esm/components/ChipChoice/components/ChipChoiceMultiple.d.ts +1 -1
- package/dist/esm/components/ChipChoice/components/ChipChoiceMultiple.js +4 -7
- package/dist/esm/components/ChipChoice/components/ChipChoiceSingle.d.ts +1 -1
- package/dist/esm/components/ChipChoice/components/ChipChoiceSingle.js +5 -8
- package/dist/esm/components/ChipChoice/components/ChipChoiceTime.d.ts +1 -1
- package/dist/esm/components/ChipChoice/components/ChipChoiceTime.js +6 -6
- package/dist/esm/components/ChipChoice/constants.d.ts +1 -0
- package/dist/esm/components/ChipChoice/constants.js +1 -0
- package/dist/esm/components/ChipChoice/types.d.ts +7 -3
- package/dist/esm/components/ChipChoiceRow/ChipChoiceRow.d.ts +12 -6
- package/dist/esm/components/ChipChoiceRow/ChipChoiceRow.js +69 -13
- package/dist/esm/components/ChipChoiceRow/components/constants.d.ts +1 -0
- package/dist/esm/components/ChipChoiceRow/components/constants.js +1 -0
- package/dist/esm/components/ChipChoiceRow/helpers.d.ts +5 -0
- package/dist/esm/components/ChipChoiceRow/helpers.js +13 -0
- package/dist/esm/components/ChipChoiceRow/index.d.ts +1 -0
- package/dist/esm/components/ChipChoiceRow/index.js +1 -0
- package/dist/esm/components/ChipChoiceRow/styles.module.css +21 -0
- package/dist/esm/components/ChipChoiceRow/types.d.ts +5 -5
- package/dist/esm/constants.d.ts +4 -1
- package/dist/esm/constants.js +4 -1
- package/package.json +7 -5
- package/src/components/ChipChoice/components/ChipChoiceBase/ChipChoiceBase.tsx +2 -7
- package/src/components/ChipChoice/components/ChipChoiceCustom.tsx +8 -9
- package/src/components/ChipChoice/components/ChipChoiceDate.tsx +8 -6
- package/src/components/ChipChoice/components/ChipChoiceDateRange.tsx +7 -7
- package/src/components/ChipChoice/components/ChipChoiceMultiple.tsx +6 -8
- package/src/components/ChipChoice/components/ChipChoiceSingle.tsx +7 -7
- package/src/components/ChipChoice/components/ChipChoiceTime.tsx +8 -6
- package/src/components/ChipChoice/constants.ts +1 -0
- package/src/components/ChipChoice/types.ts +7 -2
- package/src/components/ChipChoiceRow/ChipChoiceRow.tsx +174 -30
- package/src/components/ChipChoiceRow/components/constants.ts +1 -0
- package/src/components/ChipChoiceRow/helpers.ts +15 -0
- package/src/components/ChipChoiceRow/index.ts +1 -0
- package/src/components/ChipChoiceRow/styles.module.scss +27 -2
- package/src/components/ChipChoiceRow/types.ts +13 -4
- package/src/constants.ts +4 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ReactNode, useCallback, useRef
|
|
1
|
+
import { ReactNode, useCallback, useRef } from 'react';
|
|
2
2
|
import { useUncontrolledProp } from 'uncontrollable';
|
|
3
3
|
|
|
4
4
|
import { Calendar, CalendarProps } from '@snack-uikit/calendar';
|
|
@@ -47,6 +47,9 @@ export function ChipChoiceDateRange({
|
|
|
47
47
|
valueRender,
|
|
48
48
|
dropDownClassName,
|
|
49
49
|
buildCalendarCellProps,
|
|
50
|
+
onClearButtonClick,
|
|
51
|
+
open: openProp,
|
|
52
|
+
onOpenChange,
|
|
50
53
|
...rest
|
|
51
54
|
}: ChipChoiceDateRangeProps) {
|
|
52
55
|
const [selectedValue, setSelectedValue] = useUncontrolledProp<Range>(value, defaultValue, onChange);
|
|
@@ -56,17 +59,14 @@ export function ChipChoiceDateRange({
|
|
|
56
59
|
const valueToRender = valueRender
|
|
57
60
|
? valueRender(selectedValue)
|
|
58
61
|
: defaultRangeFormatter({ value: selectedValue, allLabel: t('allLabel') });
|
|
59
|
-
|
|
60
|
-
const clearValue = () => setSelectedValue(undefined);
|
|
61
|
-
|
|
62
62
|
const localRef = useRef<HTMLDivElement>(null);
|
|
63
63
|
|
|
64
|
-
const [open, setOpen] =
|
|
64
|
+
const [open, setOpen] = useUncontrolledProp(openProp, false, onOpenChange);
|
|
65
65
|
|
|
66
66
|
const closeDroplist = useCallback(() => {
|
|
67
67
|
setOpen(false);
|
|
68
68
|
setTimeout(() => localRef.current?.focus(), 0);
|
|
69
|
-
}, []);
|
|
69
|
+
}, [setOpen]);
|
|
70
70
|
|
|
71
71
|
const handleOnKeyDown = useHandleOnKeyDown({ setOpen });
|
|
72
72
|
|
|
@@ -98,7 +98,7 @@ export function ChipChoiceDateRange({
|
|
|
98
98
|
<ChipChoiceBase
|
|
99
99
|
{...rest}
|
|
100
100
|
ref={localRef}
|
|
101
|
-
onClearButtonClick={
|
|
101
|
+
onClearButtonClick={onClearButtonClick}
|
|
102
102
|
value={selectedValue}
|
|
103
103
|
valueToRender={valueToRender}
|
|
104
104
|
size={size}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import { useUncontrolledProp } from 'uncontrollable';
|
|
2
3
|
|
|
3
4
|
import { Droplist, ItemId, SelectionSingleValueType } from '@snack-uikit/list';
|
|
4
5
|
import { useLocale } from '@snack-uikit/locale';
|
|
@@ -43,11 +44,13 @@ export function ChipChoiceMultiple<T extends ContentRenderProps = ContentRenderP
|
|
|
43
44
|
searchable,
|
|
44
45
|
contentRender,
|
|
45
46
|
dropDownClassName,
|
|
46
|
-
|
|
47
|
+
onClearButtonClick,
|
|
47
48
|
autoApply = true,
|
|
48
49
|
disableFuzzySearch = false,
|
|
49
50
|
onApprove,
|
|
50
51
|
onCancel,
|
|
52
|
+
open: openProp,
|
|
53
|
+
onOpenChange,
|
|
51
54
|
...rest
|
|
52
55
|
}: ChipChoiceMultipleProps<T>) {
|
|
53
56
|
const [value, setValue] = useValueControl<SelectionSingleValueType[]>({
|
|
@@ -70,7 +73,7 @@ export function ChipChoiceMultiple<T extends ContentRenderProps = ContentRenderP
|
|
|
70
73
|
|
|
71
74
|
const { t } = useLocale('Chips');
|
|
72
75
|
|
|
73
|
-
const [open, setOpen] =
|
|
76
|
+
const [open, setOpen] = useUncontrolledProp(openProp, false, onOpenChange);
|
|
74
77
|
const handleOnKeyDown = useHandleOnKeyDown({ setOpen });
|
|
75
78
|
|
|
76
79
|
const flatMapOptions = useMemo(() => Object.values(flattenOptions), [flattenOptions]);
|
|
@@ -98,10 +101,6 @@ export function ChipChoiceMultiple<T extends ContentRenderProps = ContentRenderP
|
|
|
98
101
|
);
|
|
99
102
|
const items = useMemo(() => transformOptionsToItems<T>(result, contentRender), [contentRender, result]);
|
|
100
103
|
|
|
101
|
-
const clearValue = () => {
|
|
102
|
-
setValue([]);
|
|
103
|
-
setDeferredValue([]);
|
|
104
|
-
};
|
|
105
104
|
const chipRef = useRef<HTMLDivElement>(null);
|
|
106
105
|
const listRef = useRef<HTMLElement>(null);
|
|
107
106
|
|
|
@@ -192,9 +191,8 @@ export function ChipChoiceMultiple<T extends ContentRenderProps = ContentRenderP
|
|
|
192
191
|
<ChipChoiceBase
|
|
193
192
|
{...rest}
|
|
194
193
|
ref={chipRef}
|
|
195
|
-
onClearButtonClick={
|
|
194
|
+
onClearButtonClick={onClearButtonClick}
|
|
196
195
|
value={value}
|
|
197
|
-
showClearButton={showClearButton && !(Array.isArray(value) && [0].includes(value.length))}
|
|
198
196
|
valueToRender={valueToRender}
|
|
199
197
|
label={label}
|
|
200
198
|
loading={rest.loading}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import { useUncontrolledProp } from 'uncontrollable';
|
|
2
3
|
|
|
3
4
|
import { Droplist, ItemId, SelectionSingleValueType } from '@snack-uikit/list';
|
|
4
5
|
import { useLocale } from '@snack-uikit/locale';
|
|
@@ -36,6 +37,9 @@ export function ChipChoiceSingle<T extends ContentRenderProps = ContentRenderPro
|
|
|
36
37
|
autoApply = true,
|
|
37
38
|
onApprove,
|
|
38
39
|
onCancel,
|
|
40
|
+
onClearButtonClick,
|
|
41
|
+
open: openProp,
|
|
42
|
+
onOpenChange,
|
|
39
43
|
...rest
|
|
40
44
|
}: ChipChoiceSingleProps<T>) {
|
|
41
45
|
const [value, setValue] = useValueControl<SelectionSingleValueType>({
|
|
@@ -56,7 +60,7 @@ export function ChipChoiceSingle<T extends ContentRenderProps = ContentRenderPro
|
|
|
56
60
|
|
|
57
61
|
const { t } = useLocale('Chips');
|
|
58
62
|
|
|
59
|
-
const [open, setOpen] =
|
|
63
|
+
const [open, setOpen] = useUncontrolledProp(openProp, false, onOpenChange);
|
|
60
64
|
const handleOnKeyDown = useHandleOnKeyDown({ setOpen });
|
|
61
65
|
|
|
62
66
|
const flatMapOptions = useMemo(() => Object.values(flattenOptions), [flattenOptions]);
|
|
@@ -82,10 +86,6 @@ export function ChipChoiceSingle<T extends ContentRenderProps = ContentRenderPro
|
|
|
82
86
|
);
|
|
83
87
|
const items = useMemo(() => transformOptionsToItems<T>(result, contentRender), [contentRender, result]);
|
|
84
88
|
|
|
85
|
-
const clearValue = () => {
|
|
86
|
-
setValue(undefined);
|
|
87
|
-
setDeferredValue(undefined);
|
|
88
|
-
};
|
|
89
89
|
const chipRef = useRef<HTMLDivElement>(null);
|
|
90
90
|
|
|
91
91
|
const handleSelectionChange = useCallback(
|
|
@@ -102,7 +102,7 @@ export function ChipChoiceSingle<T extends ContentRenderProps = ContentRenderPro
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
},
|
|
105
|
-
[autoApply, setValue, setDeferredValue],
|
|
105
|
+
[autoApply, setOpen, setValue, setDeferredValue],
|
|
106
106
|
);
|
|
107
107
|
|
|
108
108
|
const handleOnCancelClick = () => {
|
|
@@ -175,7 +175,7 @@ export function ChipChoiceSingle<T extends ContentRenderProps = ContentRenderPro
|
|
|
175
175
|
<ChipChoiceBase
|
|
176
176
|
{...rest}
|
|
177
177
|
ref={chipRef}
|
|
178
|
-
onClearButtonClick={
|
|
178
|
+
onClearButtonClick={onClearButtonClick}
|
|
179
179
|
value={value}
|
|
180
180
|
valueToRender={valueToRender}
|
|
181
181
|
label={label}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { ReactNode, useCallback, useMemo, useRef
|
|
1
|
+
import { ReactNode, useCallback, useMemo, useRef } from 'react';
|
|
2
|
+
import { useUncontrolledProp } from 'uncontrollable';
|
|
2
3
|
|
|
3
4
|
import { TimePicker, TimePickerProps } from '@snack-uikit/calendar';
|
|
4
5
|
import { Dropdown } from '@snack-uikit/dropdown';
|
|
@@ -50,19 +51,22 @@ export function ChipChoiceTime({
|
|
|
50
51
|
dropDownClassName,
|
|
51
52
|
showSeconds = true,
|
|
52
53
|
placement,
|
|
54
|
+
onClearButtonClick,
|
|
55
|
+
open: openProp,
|
|
56
|
+
onOpenChange,
|
|
53
57
|
...rest
|
|
54
58
|
}: ChipChoiceTimeProps) {
|
|
55
59
|
const [selectedValue, setSelectedValue] = useValueControl<TimeValue>({ value, defaultValue, onChange });
|
|
56
60
|
|
|
57
61
|
const localRef = useRef<HTMLDivElement>(null);
|
|
58
62
|
|
|
59
|
-
const [open, setOpen] =
|
|
63
|
+
const [open, setOpen] = useUncontrolledProp(openProp, false, onOpenChange);
|
|
60
64
|
const handleOnKeyDown = useHandleOnKeyDown({ setOpen });
|
|
61
65
|
|
|
62
66
|
const closeDroplist = useCallback(() => {
|
|
63
67
|
setOpen(false);
|
|
64
68
|
setTimeout(() => localRef.current?.focus(), 0);
|
|
65
|
-
}, []);
|
|
69
|
+
}, [setOpen]);
|
|
66
70
|
|
|
67
71
|
const { t } = useLocale('Chips');
|
|
68
72
|
|
|
@@ -76,8 +80,6 @@ export function ChipChoiceTime({
|
|
|
76
80
|
return getStringTimeValue(selectedValue, { showSeconds, locale: DEFAULT_LOCALE });
|
|
77
81
|
}, [selectedValue, showSeconds, t, valueRender]);
|
|
78
82
|
|
|
79
|
-
const clearValue = () => setSelectedValue(undefined);
|
|
80
|
-
|
|
81
83
|
const handleChangeValue = useCallback(
|
|
82
84
|
(value: TimeValue) => {
|
|
83
85
|
setSelectedValue(value);
|
|
@@ -114,7 +116,7 @@ export function ChipChoiceTime({
|
|
|
114
116
|
<ChipChoiceBase
|
|
115
117
|
{...rest}
|
|
116
118
|
ref={localRef}
|
|
117
|
-
onClearButtonClick={
|
|
119
|
+
onClearButtonClick={onClearButtonClick}
|
|
118
120
|
value={selectedValue}
|
|
119
121
|
valueToRender={valueToRender}
|
|
120
122
|
size={size}
|
|
@@ -79,8 +79,8 @@ export type ChipChoiceCommonProps = WithSupportProps<
|
|
|
79
79
|
* @default false
|
|
80
80
|
*/
|
|
81
81
|
disableFuzzySearch?: boolean;
|
|
82
|
-
/**
|
|
83
|
-
|
|
82
|
+
/** Колбек для клика по кнопке очистки */
|
|
83
|
+
onClearButtonClick?: MouseEventHandler<HTMLButtonElement>;
|
|
84
84
|
/** Расположение выпадающего меню */
|
|
85
85
|
placement?: DropdownProps['placement'];
|
|
86
86
|
/**
|
|
@@ -92,6 +92,10 @@ export type ChipChoiceCommonProps = WithSupportProps<
|
|
|
92
92
|
*/
|
|
93
93
|
widthStrategy?: DropdownProps['widthStrategy'];
|
|
94
94
|
dropDownClassName?: string;
|
|
95
|
+
/** Управляет состоянием показан/не показан. */
|
|
96
|
+
open?: boolean;
|
|
97
|
+
/** Колбек отображения компонента. Срабатывает при изменении состояния open. */
|
|
98
|
+
onOpenChange?: (isOpen: boolean) => void;
|
|
95
99
|
}
|
|
96
100
|
>;
|
|
97
101
|
|
|
@@ -123,6 +127,7 @@ export type ChipChoiceSelectCommonProps<T extends ContentRenderProps = ContentRe
|
|
|
123
127
|
| 'noResultsState'
|
|
124
128
|
| 'loading'
|
|
125
129
|
| 'scrollToSelectedItem'
|
|
130
|
+
| 'virtualized'
|
|
126
131
|
>;
|
|
127
132
|
|
|
128
133
|
export type ChipChoiceSingleProps<T extends ContentRenderProps = ContentRenderProps> = ChipChoiceSelectCommonProps<T> &
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import cn from 'classnames';
|
|
2
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
3
|
import { useUncontrolledProp } from 'uncontrollable';
|
|
3
4
|
|
|
4
5
|
import { ButtonFunction } from '@snack-uikit/button';
|
|
5
|
-
import {
|
|
6
|
+
import { Divider } from '@snack-uikit/divider';
|
|
7
|
+
import { CrossSVG, PlusSVG } from '@snack-uikit/icons';
|
|
8
|
+
import { Droplist, DroplistProps } from '@snack-uikit/list';
|
|
6
9
|
import { useLocale } from '@snack-uikit/locale';
|
|
10
|
+
import { Tooltip } from '@snack-uikit/tooltip';
|
|
7
11
|
import { extractSupportProps, WithSupportProps } from '@snack-uikit/utils';
|
|
8
12
|
|
|
9
13
|
import { CHIP_CHOICE_ROW_IDS } from '../../constants';
|
|
@@ -14,7 +18,9 @@ import { ChipChoiceProps, ChipChoiceRowSize, FilterValue, OmitBetter } from './t
|
|
|
14
18
|
|
|
15
19
|
export type FiltersState = Record<string, unknown>;
|
|
16
20
|
|
|
17
|
-
export type ChipChoiceRowFilter = OmitBetter<ChipChoiceProps, 'onChange' | 'value' | 'size' | 'defaultValue'
|
|
21
|
+
export type ChipChoiceRowFilter = OmitBetter<ChipChoiceProps, 'onChange' | 'value' | 'size' | 'defaultValue'> & {
|
|
22
|
+
pinned?: boolean;
|
|
23
|
+
};
|
|
18
24
|
|
|
19
25
|
export type ChipChoiceRowProps<TState extends FiltersState> = WithSupportProps<{
|
|
20
26
|
/** Состояние фильтров */
|
|
@@ -29,32 +35,51 @@ export type ChipChoiceRowProps<TState extends FiltersState> = WithSupportProps<{
|
|
|
29
35
|
size?: ChipChoiceRowSize;
|
|
30
36
|
/** CSS-класс */
|
|
31
37
|
className?: string;
|
|
32
|
-
/** Скрыть/показать кнопку очиски @default true */
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
|
|
38
|
+
/** Скрыть/показать кнопку очиски фильтров @default true */
|
|
39
|
+
showClearButton?: boolean;
|
|
40
|
+
/** Скрыть/показать кнопку добавления фильров @default true */
|
|
41
|
+
showAddButton?: boolean;
|
|
42
|
+
/** Состояние для видимых фильтров */
|
|
43
|
+
visibleFilters?: string[];
|
|
44
|
+
/** Коллбек на изменение видимых фильтров */
|
|
45
|
+
onVisibleFiltersChange?(value: string[]): void;
|
|
36
46
|
}>;
|
|
37
47
|
|
|
38
48
|
export function ChipChoiceRow<TState extends FiltersState>({
|
|
39
49
|
filters,
|
|
40
50
|
onChange,
|
|
41
|
-
|
|
42
|
-
|
|
51
|
+
showClearButton = true,
|
|
52
|
+
showAddButton = true,
|
|
43
53
|
className,
|
|
44
54
|
value,
|
|
45
|
-
defaultValue,
|
|
55
|
+
defaultValue: defaultValueProp,
|
|
46
56
|
size = CHIP_CHOICE_ROW_SIZE.S,
|
|
57
|
+
visibleFilters: visibleFiltersProp,
|
|
58
|
+
onVisibleFiltersChange,
|
|
47
59
|
...rest
|
|
48
60
|
}: ChipChoiceRowProps<TState>) {
|
|
49
61
|
const { t } = useLocale('Chips');
|
|
50
62
|
|
|
51
|
-
const
|
|
63
|
+
const defaultValue = useMemo(() => (defaultValueProp ?? {}) as TState, [defaultValueProp]);
|
|
52
64
|
|
|
53
|
-
const [state, setState] = useUncontrolledProp<TState>(value,
|
|
65
|
+
const [state, setState] = useUncontrolledProp<TState>(value, defaultValue, newState => {
|
|
54
66
|
const result = typeof newState === 'function' ? newState(state) : newState;
|
|
55
67
|
onChange?.(result);
|
|
56
68
|
});
|
|
57
69
|
|
|
70
|
+
const [addListValue, setAddListValue] = useUncontrolledProp<string[]>(
|
|
71
|
+
visibleFiltersProp,
|
|
72
|
+
Object.keys(state),
|
|
73
|
+
newState => {
|
|
74
|
+
const result = typeof newState === 'function' ? newState(addListValue) : newState;
|
|
75
|
+
onVisibleFiltersChange?.(result);
|
|
76
|
+
},
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const [openedChip, setOpenedChip] = useState<string>('');
|
|
80
|
+
|
|
81
|
+
const [addListOpen, setAddListOpen] = useState(false);
|
|
82
|
+
|
|
58
83
|
const handleChange = (fieldId: string, value: FilterValue) => {
|
|
59
84
|
setState((state: TState) => ({
|
|
60
85
|
...state,
|
|
@@ -62,44 +87,163 @@ export function ChipChoiceRow<TState extends FiltersState>({
|
|
|
62
87
|
}));
|
|
63
88
|
};
|
|
64
89
|
|
|
90
|
+
const handleChipOpen = useCallback(
|
|
91
|
+
(filterId: string) => (isOpen: boolean) => {
|
|
92
|
+
setOpenedChip(isOpen ? filterId : '');
|
|
93
|
+
},
|
|
94
|
+
[],
|
|
95
|
+
);
|
|
96
|
+
|
|
65
97
|
const handleFiltersClear = () => {
|
|
66
|
-
|
|
98
|
+
const defaultState = filters.reduce((res, filter) => {
|
|
99
|
+
if (filter.pinned) {
|
|
100
|
+
return { ...res, [filter.id]: defaultValue[filter.id] } as TState;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return res;
|
|
104
|
+
}, {} as TState);
|
|
105
|
+
|
|
106
|
+
setState(defaultState);
|
|
107
|
+
setAddListValue([]);
|
|
67
108
|
};
|
|
68
109
|
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
110
|
+
const pinnedFilters = useMemo(() => filters.filter(filter => filter.pinned), [filters]);
|
|
111
|
+
const nonPinnedFilters = useMemo(() => filters.filter(filter => !filter.pinned), [filters]);
|
|
112
|
+
|
|
113
|
+
const visibleFilters = useMemo(
|
|
114
|
+
() =>
|
|
115
|
+
addListValue
|
|
116
|
+
.map(filterId => nonPinnedFilters.find(filter => filter.id === filterId))
|
|
117
|
+
.filter((item): item is ChipChoiceRowFilter => Boolean(item)),
|
|
118
|
+
[addListValue, nonPinnedFilters],
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
const hasAnyFilter = useMemo(
|
|
122
|
+
() => visibleFilters.length > 0 || pinnedFilters.some(filter => state[filter.id] !== defaultValue[filter.id]),
|
|
123
|
+
[defaultValue, pinnedFilters, state, visibleFilters.length],
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
const handleClearPinnedFilter = (filterId: string) => {
|
|
127
|
+
const defaultFilterValue = defaultValue[filterId];
|
|
128
|
+
|
|
129
|
+
if (state[filterId] === defaultFilterValue) {
|
|
130
|
+
return;
|
|
72
131
|
}
|
|
73
132
|
|
|
74
|
-
|
|
75
|
-
|
|
133
|
+
return () => setState((prevState: TState) => ({ ...prevState, [filterId]: defaultFilterValue }));
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const handleRemoveVisibleFilter = (filterId: string) => () => {
|
|
137
|
+
setAddListValue((prev?: string[]) => prev?.filter(item => filterId !== item));
|
|
138
|
+
setState((prevState: TState) => ({ ...prevState, [filterId]: undefined }));
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const addSelectorOptions: DroplistProps['items'] = useMemo(
|
|
142
|
+
() =>
|
|
143
|
+
nonPinnedFilters
|
|
144
|
+
.filter(filter => !addListValue.includes(filter.id))
|
|
145
|
+
.map((filter, index) => ({
|
|
146
|
+
id: filter.id,
|
|
147
|
+
content: { option: filter.label ?? filter.id },
|
|
148
|
+
onClick: () => {
|
|
149
|
+
setAddListValue(function (prevValue?: string[]) {
|
|
150
|
+
return [...(prevValue ?? []), filter.id];
|
|
151
|
+
});
|
|
152
|
+
setAddListOpen(false);
|
|
153
|
+
},
|
|
154
|
+
'data-test-id': `${CHIP_CHOICE_ROW_IDS.addButtonOption}-${filter['data-test-id'] ?? index}`,
|
|
155
|
+
})),
|
|
156
|
+
[addListValue, nonPinnedFilters, setAddListValue],
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
const canAddChips = addSelectorOptions.length > 0;
|
|
160
|
+
|
|
161
|
+
const addListPrevValue = useRef(addListValue);
|
|
162
|
+
|
|
163
|
+
useEffect(() => {
|
|
164
|
+
const prevValue = addListPrevValue.current;
|
|
165
|
+
|
|
166
|
+
if (addListValue.length > prevValue.length) {
|
|
167
|
+
const newItem = addListValue.find(item => !prevValue.includes(item));
|
|
168
|
+
|
|
169
|
+
if (newItem) {
|
|
170
|
+
handleChipOpen(newItem)(true);
|
|
171
|
+
}
|
|
76
172
|
}
|
|
77
173
|
|
|
78
|
-
|
|
79
|
-
});
|
|
174
|
+
addListPrevValue.current = addListValue;
|
|
175
|
+
}, [addListValue, handleChipOpen]);
|
|
80
176
|
|
|
81
177
|
return (
|
|
82
178
|
<div className={cn(styles.chipChoiceRow, className)} {...extractSupportProps(rest)}>
|
|
83
|
-
{
|
|
179
|
+
{pinnedFilters.length > 0 && (
|
|
180
|
+
<div className={styles.pinnedItems}>
|
|
181
|
+
{pinnedFilters.map(filter => (
|
|
182
|
+
<ForwardedChipChoice
|
|
183
|
+
key={filter.id}
|
|
184
|
+
{...filter}
|
|
185
|
+
value={state[filter.id] as never}
|
|
186
|
+
size={MAP_ROW_SIZE_TO_CHOICE_SIZE[size]}
|
|
187
|
+
onChange={(value: FilterValue) => handleChange(filter.id, value)}
|
|
188
|
+
onClearButtonClick={handleClearPinnedFilter(filter.id)}
|
|
189
|
+
/>
|
|
190
|
+
))}
|
|
191
|
+
|
|
192
|
+
<Divider orientation='vertical' className={styles.divider} />
|
|
193
|
+
</div>
|
|
194
|
+
)}
|
|
195
|
+
|
|
196
|
+
{visibleFilters.map(filter => (
|
|
84
197
|
<ForwardedChipChoice
|
|
85
198
|
key={filter.id}
|
|
86
199
|
{...filter}
|
|
87
200
|
value={state[filter.id] as never}
|
|
88
201
|
size={MAP_ROW_SIZE_TO_CHOICE_SIZE[size]}
|
|
89
202
|
onChange={(value: FilterValue) => handleChange(filter.id, value)}
|
|
203
|
+
onClearButtonClick={handleRemoveVisibleFilter(filter.id)}
|
|
204
|
+
open={openedChip === filter.id}
|
|
205
|
+
onOpenChange={handleChipOpen(filter.id)}
|
|
90
206
|
/>
|
|
91
207
|
))}
|
|
92
208
|
|
|
93
|
-
{
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
209
|
+
<div className={styles.controlWrapper}>
|
|
210
|
+
{showAddButton && (
|
|
211
|
+
<Tooltip
|
|
212
|
+
tip={t('addButtonDisabledTip')}
|
|
213
|
+
open={canAddChips ? false : undefined}
|
|
214
|
+
placement='bottom'
|
|
215
|
+
data-test-id={CHIP_CHOICE_ROW_IDS.addButtonTooltip}
|
|
216
|
+
>
|
|
217
|
+
<Droplist
|
|
218
|
+
open={canAddChips && addListOpen}
|
|
219
|
+
onOpenChange={setAddListOpen}
|
|
220
|
+
items={addSelectorOptions}
|
|
221
|
+
triggerClassName={styles.addButtonWrapper}
|
|
222
|
+
trigger='clickAndFocusVisible'
|
|
223
|
+
>
|
|
224
|
+
<ButtonFunction
|
|
225
|
+
disabled={!canAddChips}
|
|
226
|
+
label={t('add')}
|
|
227
|
+
icon={<PlusSVG />}
|
|
228
|
+
iconPosition='before'
|
|
229
|
+
size={MAP_ROW_SIZE_TO_BUTTON_SIZE[size]}
|
|
230
|
+
data-test-id={CHIP_CHOICE_ROW_IDS.addButton}
|
|
231
|
+
/>
|
|
232
|
+
</Droplist>
|
|
233
|
+
</Tooltip>
|
|
234
|
+
)}
|
|
235
|
+
|
|
236
|
+
{showClearButton && hasAnyFilter && (
|
|
237
|
+
<ButtonFunction
|
|
238
|
+
onClick={handleFiltersClear}
|
|
239
|
+
label={t('clear')}
|
|
240
|
+
icon={<CrossSVG />}
|
|
241
|
+
iconPosition='before'
|
|
242
|
+
size={MAP_ROW_SIZE_TO_BUTTON_SIZE[size]}
|
|
243
|
+
data-test-id={CHIP_CHOICE_ROW_IDS.clearButton}
|
|
244
|
+
/>
|
|
245
|
+
)}
|
|
246
|
+
</div>
|
|
103
247
|
</div>
|
|
104
248
|
);
|
|
105
249
|
}
|
|
@@ -6,6 +6,7 @@ export const MAP_CHIP_TYPE_TO_COMPONENT = {
|
|
|
6
6
|
[CHIP_CHOICE_TYPE.Multiple]: ChipChoice.Multiple,
|
|
7
7
|
[CHIP_CHOICE_TYPE.Date]: ChipChoice.Date,
|
|
8
8
|
[CHIP_CHOICE_TYPE.DateTime]: ChipChoice.Date,
|
|
9
|
+
[CHIP_CHOICE_TYPE.Time]: ChipChoice.Time,
|
|
9
10
|
[CHIP_CHOICE_TYPE.DateRange]: ChipChoice.DateRange,
|
|
10
11
|
[CHIP_CHOICE_TYPE.Custom]: ChipChoice.Custom,
|
|
11
12
|
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* функция проверки заполненности фильтра
|
|
3
|
+
* @function hasFilterBeenApplied
|
|
4
|
+
*/
|
|
5
|
+
export function hasFilterBeenApplied(filter: unknown): boolean {
|
|
6
|
+
if (Array.isArray(filter)) {
|
|
7
|
+
return filter.length > 0 && Object.values(filter).some(Boolean);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (filter && typeof filter === 'object') {
|
|
11
|
+
return Object.values(filter).some(Boolean) || filter instanceof Date;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return Boolean(filter);
|
|
15
|
+
}
|
|
@@ -1,8 +1,33 @@
|
|
|
1
|
-
@use '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-chips-chipChoice';
|
|
1
|
+
@use '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-chips-chipChoice' as chips;
|
|
2
2
|
|
|
3
3
|
.chipChoiceRow {
|
|
4
|
-
@include
|
|
4
|
+
@include chips.composite-var(chips.$chip-choice-row-container);
|
|
5
5
|
|
|
6
6
|
display: flex;
|
|
7
7
|
flex-wrap: wrap;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.pinnedItems {
|
|
11
|
+
@include chips.composite-var(chips.$chip-choice-row-pinned);
|
|
12
|
+
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-wrap: wrap;
|
|
15
|
+
//height: min-content;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.controlWrapper {
|
|
19
|
+
@include chips.composite-var(chips.$chip-choice-row-control-wrapper);
|
|
20
|
+
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-wrap: nowrap;
|
|
23
|
+
//height: min-content;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.divider {
|
|
27
|
+
align-self: stretch;
|
|
28
|
+
height: auto;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.addButtonWrapper {
|
|
32
|
+
display: inline-flex;
|
|
8
33
|
}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { ValueOf } from '@snack-uikit/utils';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
import {
|
|
4
|
+
ChipChoiceCustomProps,
|
|
5
|
+
ChipChoiceDateProps,
|
|
6
|
+
ChipChoiceDateRangeProps,
|
|
7
|
+
ChipChoiceMultipleProps,
|
|
8
|
+
ChipChoiceSingleProps,
|
|
9
|
+
ChipChoiceTimeProps,
|
|
10
|
+
} from '../ChipChoice';
|
|
6
11
|
import { CHIP_CHOICE_TYPE } from '../ChipChoice/constants';
|
|
7
|
-
import { ChipChoiceMultipleProps, ChipChoiceSingleProps } from '../ChipChoice/types';
|
|
8
12
|
import { CHIP_CHOICE_ROW_SIZE } from './constants';
|
|
9
13
|
|
|
10
14
|
export type ChipChoiceRowSize = ValueOf<typeof CHIP_CHOICE_ROW_SIZE>;
|
|
@@ -25,6 +29,10 @@ type ChipChoiceDateTimeType = {
|
|
|
25
29
|
type: typeof CHIP_CHOICE_TYPE.DateTime;
|
|
26
30
|
} & Omit<ChipChoiceDateProps, 'mode'> & { mode: 'date-time'; showSeconds?: boolean };
|
|
27
31
|
|
|
32
|
+
type ChipChoiceTimeType = {
|
|
33
|
+
type: typeof CHIP_CHOICE_TYPE.Time;
|
|
34
|
+
} & ChipChoiceTimeProps;
|
|
35
|
+
|
|
28
36
|
type ChipChoiceDateRangeType = {
|
|
29
37
|
type: typeof CHIP_CHOICE_TYPE.DateRange;
|
|
30
38
|
} & ChipChoiceDateRangeProps;
|
|
@@ -40,6 +48,7 @@ export type ChipChoiceProps = {
|
|
|
40
48
|
| ChipChoiceSingleType
|
|
41
49
|
| ChipChoiceDateType
|
|
42
50
|
| ChipChoiceDateTimeType
|
|
51
|
+
| ChipChoiceTimeType
|
|
43
52
|
| ChipChoiceDateRangeType
|
|
44
53
|
| ChipChoiceCustomType
|
|
45
54
|
);
|
package/src/constants.ts
CHANGED
|
@@ -34,7 +34,10 @@ export const CHIP_CHOICE_TEST_IDS = {
|
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
export const CHIP_CHOICE_ROW_IDS = {
|
|
37
|
-
|
|
37
|
+
clearButton: 'chip-choice-row__clear-button',
|
|
38
|
+
addButton: 'chip-choice-row__add-button',
|
|
39
|
+
addButtonTooltip: 'chip-choice-row__add-button-tooltip',
|
|
40
|
+
addButtonOption: 'chip-choice-row__add-button-option',
|
|
38
41
|
};
|
|
39
42
|
|
|
40
43
|
export const CHIP_TOGGLE_TEST_IDS = {
|