Skip to content

Commit b79f0b0

Browse files
NowelyIlyin Ruslankorvin89
authored
feat(Select): extend return type of renderCounter prop (#2476)
Co-authored-by: Ilyin Ruslan <[email protected]> Co-authored-by: Mr.Dr.Professor Patrick <[email protected]>
1 parent ff62a77 commit b79f0b0

File tree

8 files changed

+334
-1
lines changed

8 files changed

+334
-1
lines changed

src/components/Select/README-ru.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,115 @@ const MyComponent = () => {
10131013

10141014
<!--/GITHUB_BLOCK-->
10151015

1016+
### Отображение пользовательского счетчика
1017+
1018+
Для отображения пользовательского счетчика используйте свойство `renderCounter`. Счетчик отображается только при включенном множественном выборе (`multiple={true}`) и `hasCounter={true}`.
1019+
1020+
<!--LANDING_BLOCK
1021+
1022+
<ExampleBlock
1023+
code={`
1024+
<Select
1025+
multiple={true}
1026+
hasCounter={true}
1027+
renderCounter={(_, {count, disabled}) => {
1028+
if (count === 0) {
1029+
return null;
1030+
}
1031+
if (count >= 2) {
1032+
return (
1033+
<div
1034+
style={{
1035+
padding: '0 8px',
1036+
color: disabled ? '#999' : '#027bf3',
1037+
fontWeight: 'bold',
1038+
}}
1039+
>
1040+
+{count}
1041+
</div>
1042+
);
1043+
}
1044+
return count;
1045+
}}
1046+
>
1047+
<Select.Option value="val_1">Value 1</Select.Option>
1048+
<Select.Option value="val_2">Value 2</Select.Option>
1049+
<Select.Option value="val_3">Value 3</Select.Option>
1050+
<Select.Option value="val_4">Value 4</Select.Option>
1051+
</Select>
1052+
`}
1053+
>
1054+
<UIKit.Select
1055+
multiple={true}
1056+
hasCounter={true}
1057+
renderCounter={(_, {count, disabled}) => {
1058+
if (count === 0) {
1059+
return null;
1060+
}
1061+
if (count >= 2) {
1062+
return (
1063+
<div
1064+
style={{
1065+
padding: '0 8px',
1066+
color: disabled ? '#999' : '#027bf3',
1067+
fontWeight: 'bold',
1068+
}}
1069+
>
1070+
+{count}
1071+
</div>
1072+
);
1073+
}
1074+
return count;
1075+
}}
1076+
>
1077+
<UIKit.Select.Option value="val_1">Value 1</UIKit.Select.Option>
1078+
<UIKit.Select.Option value="val_2">Value 2</UIKit.Select.Option>
1079+
<UIKit.Select.Option value="val_3">Value 3</UIKit.Select.Option>
1080+
<UIKit.Select.Option value="val_4">Value 4</UIKit.Select.Option>
1081+
</UIKit.Select>
1082+
</ExampleBlock>
1083+
1084+
LANDING_BLOCK-->
1085+
1086+
<!--GITHUB_BLOCK-->
1087+
1088+
```tsx
1089+
import type {SelectProps} from '@gravity-ui/uikit';
1090+
1091+
const MyComponent = () => {
1092+
const renderCounter: SelectProps['renderCounter'] = (_, {count, disabled}) => {
1093+
if (count === 0) {
1094+
return null;
1095+
}
1096+
if (count >= 2) {
1097+
return (
1098+
<div
1099+
style={{
1100+
padding: '0 8px',
1101+
color: disabled ? '#999' : '#027bf3',
1102+
fontWeight: 'bold',
1103+
}}
1104+
>
1105+
+{count}
1106+
</div>
1107+
);
1108+
}
1109+
return count;
1110+
};
1111+
1112+
return (
1113+
<Select multiple={true} hasCounter={true} renderCounter={renderCounter}>
1114+
<Select.Option value="val_1">Value 1</Select.Option>
1115+
<Select.Option value="val_2">Value 2</Select.Option>
1116+
<Select.Option value="val_3">Value 3</Select.Option>
1117+
<Select.Option value="val_4">Value 4</Select.Option>
1118+
</Select>
1119+
);
1120+
};
1121+
```
1122+
1123+
<!--/GITHUB_BLOCK-->
1124+
10161125
### Отображение пользовательских всплывающих окон
10171126

10181127
Для отображения пользовательских всплывающих окон используйте свойство `renderPopup`.
@@ -1150,6 +1259,7 @@ LANDING_BLOCK-->
11501259
| [popupWidth](#popup-width) | Ширина всплывающего окна. | `number \| 'fit' \| 'outfit'` | `'outfit'` |
11511260
| qa | Атрибут идентификатора для тестирования (`data-qa`). | `string` | |
11521261
| [renderControl](#render-custom-control) | Используется для рендеринга пользовательского контрола. | `function` | |
1262+
| [renderCounter](#render-custom-counter) | Используется для рендеринга пользовательского счетчика. Работает только с [hasCounter](#counter). | `function` | |
11531263
| renderEmptyOptions | Используется для рендеринга узла для пустого списка вариантов. | `function` | |
11541264
| [renderFilter](#render-custom-filter-section) | Используется для рендеринга секции пользовательской фильтрации. | `function` | |
11551265
| [renderOption](#render-custom-options) | Используется для рендеринга пользовательских вариантов. | `function` | |

src/components/Select/README.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,6 +1018,115 @@ const MyComponent = () => {
10181018

10191019
<!--/GITHUB_BLOCK-->
10201020

1021+
### Rendering custom counter
1022+
1023+
To render a custom counter, use the `renderCounter` property. The counter is only displayed when multiple selection is enabled (`multiple={true}`) and `hasCounter={true}`.
1024+
1025+
<!--LANDING_BLOCK
1026+
1027+
<ExampleBlock
1028+
code={`
1029+
<Select
1030+
multiple={true}
1031+
hasCounter={true}
1032+
renderCounter={(_, {count, disabled}) => {
1033+
if (count === 0) {
1034+
return null;
1035+
}
1036+
if (count >= 2) {
1037+
return (
1038+
<div
1039+
style={{
1040+
padding: '0 8px',
1041+
color: disabled ? '#999' : '#027bf3',
1042+
fontWeight: 'bold',
1043+
}}
1044+
>
1045+
+{count}
1046+
</div>
1047+
);
1048+
}
1049+
return count;
1050+
}}
1051+
>
1052+
<Select.Option value="val_1">Value 1</Select.Option>
1053+
<Select.Option value="val_2">Value 2</Select.Option>
1054+
<Select.Option value="val_3">Value 3</Select.Option>
1055+
<Select.Option value="val_4">Value 4</Select.Option>
1056+
</Select>
1057+
`}
1058+
>
1059+
<UIKit.Select
1060+
multiple={true}
1061+
hasCounter={true}
1062+
renderCounter={(_, {count, disabled}) => {
1063+
if (count === 0) {
1064+
return null;
1065+
}
1066+
if (count >= 2) {
1067+
return (
1068+
<div
1069+
style={{
1070+
padding: '0 8px',
1071+
color: disabled ? '#999' : '#027bf3',
1072+
fontWeight: 'bold',
1073+
}}
1074+
>
1075+
+{count}
1076+
</div>
1077+
);
1078+
}
1079+
return count;
1080+
}}
1081+
>
1082+
<UIKit.Select.Option value="val_1">Value 1</UIKit.Select.Option>
1083+
<UIKit.Select.Option value="val_2">Value 2</UIKit.Select.Option>
1084+
<UIKit.Select.Option value="val_3">Value 3</UIKit.Select.Option>
1085+
<UIKit.Select.Option value="val_4">Value 4</UIKit.Select.Option>
1086+
</UIKit.Select>
1087+
</ExampleBlock>
1088+
1089+
LANDING_BLOCK-->
1090+
1091+
<!--GITHUB_BLOCK-->
1092+
1093+
```tsx
1094+
import type {SelectProps} from '@gravity-ui/uikit';
1095+
1096+
const MyComponent = () => {
1097+
const renderCounter: SelectProps['renderCounter'] = (_, {count, disabled}) => {
1098+
if (count === 0) {
1099+
return null;
1100+
}
1101+
if (count >= 2) {
1102+
return (
1103+
<div
1104+
style={{
1105+
padding: '0 8px',
1106+
color: disabled ? '#999' : '#027bf3',
1107+
fontWeight: 'bold',
1108+
}}
1109+
>
1110+
+{count}
1111+
</div>
1112+
);
1113+
}
1114+
return count;
1115+
};
1116+
1117+
return (
1118+
<Select multiple={true} hasCounter={true} renderCounter={renderCounter}>
1119+
<Select.Option value="val_1">Value 1</Select.Option>
1120+
<Select.Option value="val_2">Value 2</Select.Option>
1121+
<Select.Option value="val_3">Value 3</Select.Option>
1122+
<Select.Option value="val_4">Value 4</Select.Option>
1123+
</Select>
1124+
);
1125+
};
1126+
```
1127+
1128+
<!--/GITHUB_BLOCK-->
1129+
10211130
### Rendering custom popup
10221131

10231132
To render custom popup, use the `renderPopup` property.
@@ -1184,6 +1293,7 @@ LANDING_BLOCK-->
11841293
| [popupWidth](#popup-width) | Popup width | `number \| 'fit' \| 'outfit'` | `'outfit'` |
11851294
| qa | Test id attribute (`data-qa`) | `string` | |
11861295
| [renderControl](#render-custom-control) | Used to render user control | `function` | |
1296+
| [renderCounter](#rendering-custom-counter) | Used to render user counter. Works only with [hasCounter](#counter). | `function` | |
11871297
| renderEmptyOptions | Used to render a node for an empty option list | `function` | |
11881298
| [renderFilter](#render-custom-filter-section) | Used to render user filter section | `function` | |
11891299
| [renderOption](#render-custom-options) | Used to render user options | `function` | |

src/components/Select/__stories__/Select.stories.tsx

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,3 +563,72 @@ export const WithInsideError: Story = {
563563
},
564564
render: WithOutsideError.render,
565565
};
566+
567+
export const WithCounter: Story = {
568+
tags: ['!dev'],
569+
decorators: [WithTitle],
570+
args: {
571+
...showcaseArgs,
572+
multiple: true,
573+
hasCounter: true,
574+
value: ['val1', 'val2'],
575+
},
576+
render: (args) => {
577+
const [{value}, setArgs] = useArgs<typeof args>();
578+
579+
return (
580+
<Select {...args} value={value} onUpdate={(values) => setArgs({value: values})}>
581+
<Select.Option value="val1" content="Value1" />
582+
<Select.Option value="val2" content="Value2" />
583+
<Select.Option value="val3" content="Value3" />
584+
<Select.Option value="val4" content="Value4" />
585+
</Select>
586+
);
587+
},
588+
};
589+
590+
export const WithCustomCounter: Story = {
591+
tags: ['!dev'],
592+
decorators: [WithTitle],
593+
args: {
594+
...showcaseArgs,
595+
multiple: true,
596+
hasCounter: true,
597+
value: ['val1', 'val2', 'val3'],
598+
},
599+
render: (args) => {
600+
const [{value}, setArgs] = useArgs<typeof args>();
601+
602+
return (
603+
<Select
604+
{...args}
605+
value={value}
606+
onUpdate={(values) => setArgs({value: values})}
607+
renderCounter={(_, {count, disabled}) => {
608+
if (count === 0) {
609+
return null;
610+
}
611+
if (count >= 2) {
612+
return (
613+
<div
614+
style={{
615+
padding: '0 8px',
616+
color: disabled ? '#999' : '#027bf3',
617+
fontWeight: 'bold',
618+
}}
619+
>
620+
+{count}
621+
</div>
622+
);
623+
}
624+
return count;
625+
}}
626+
>
627+
<Select.Option value="val1" content="Value1" />
628+
<Select.Option value="val2" content="Value2" />
629+
<Select.Option value="val3" content="Value3" />
630+
<Select.Option value="val4" content="Value4" />
631+
</Select>
632+
);
633+
},
634+
};

src/components/Select/__stories__/Showcase.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import * as Stories from './Select.stories';
1414
<Canvas of={Stories.WithCustomRendererAndTooltipAtDisabledItem} />
1515
<Canvas of={Stories.WithCustomFilterSection} />
1616
<Canvas of={Stories.WithCustomPopup} />
17+
<Canvas of={Stories.WithCounter} />
18+
<Canvas of={Stories.WithCustomCounter} />
1719

1820
## With errors
1921

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import userEvent from '@testing-library/user-event';
2+
3+
import {SelectQa} from '../constants';
4+
5+
import {DEFAULT_OPTIONS, TEST_QA, setup} from './utils';
6+
7+
const CUSTOM_COUNTER_QA = 'custom-counter-qa';
8+
9+
describe('Select renderCounter', () => {
10+
test('renders custom counter instead of default', () => {
11+
const {getByTestId, queryByTestId} = setup({
12+
multiple: true,
13+
hasCounter: true,
14+
value: [DEFAULT_OPTIONS[0].value],
15+
renderCounter: () => <div data-qa={CUSTOM_COUNTER_QA}>Custom: 1</div>,
16+
});
17+
18+
expect(getByTestId(CUSTOM_COUNTER_QA)).toBeInTheDocument();
19+
expect(queryByTestId(SelectQa.COUNTER)).not.toBeInTheDocument();
20+
});
21+
22+
test('can return null for conditional rendering', async () => {
23+
const {queryByTestId, getByTestId, getByText} = setup({
24+
multiple: true,
25+
hasCounter: true,
26+
renderCounter: (_, {count}) =>
27+
count === 0 ? null : <div data-qa={CUSTOM_COUNTER_QA}>+{count}</div>,
28+
});
29+
30+
expect(queryByTestId(CUSTOM_COUNTER_QA)).not.toBeInTheDocument();
31+
32+
const user = userEvent.setup();
33+
await user.click(getByTestId(TEST_QA)); // open
34+
await user.click(getByText(DEFAULT_OPTIONS[0].content as string)); // select
35+
36+
expect(getByTestId(CUSTOM_COUNTER_QA)).toBeInTheDocument();
37+
expect(getByTestId(CUSTOM_COUNTER_QA)).toHaveTextContent('+1');
38+
});
39+
});

src/components/Select/components/SelectCounter/SelectCounter.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {Text} from '../../../Text';
22
import {block} from '../../../utils/cn';
3+
import {SelectQa} from '../../constants';
34
import type {SelectCounterProps} from '../../types';
45

56
import './SelectCounter.scss';
@@ -13,6 +14,7 @@ export function SelectCounter({count, size, disabled}: SelectCounterProps) {
1314
variant={size === 'xl' ? 'body-2' : 'body-1'}
1415
color={disabled ? 'hint' : 'primary'}
1516
className={b('text')}
17+
qa={SelectQa.COUNTER}
1618
>
1719
{count}
1820
</Text>

src/components/Select/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export const SelectQa = {
3737
SHEET: 'select-sheet',
3838
CLEAR: 'select-clear',
3939
FILTER_INPUT: 'select-filter-input',
40+
COUNTER: 'select-counter',
4041
};
4142

4243
export const FLATTEN_KEY = Symbol('flatten');

0 commit comments

Comments
 (0)