Skip to content

Commit

Permalink
feat(select): allow to use options as selected value (#393)
Browse files Browse the repository at this point in the history
  • Loading branch information
reme3d2y committed Dec 2, 2020
1 parent 1d3cb6b commit a16f47a
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 9 deletions.
29 changes: 28 additions & 1 deletion packages/select/src/Component.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ import { Select } from '@alfalab/core-components-select';
<Preview>
<div style={{ height: 180, width: 300 }}>
{React.createElement(() => {
const [selected, setSelected] = React.useState([options[8].value, options[9].value]);
const [selected, setSelected] = React.useState([options[8].key, options[9].key]);
const handleChange = ({ selectedMultiple }) => {
setSelected(selectedMultiple.map(option => option.key));
};
Expand All @@ -195,6 +195,33 @@ import { Select } from '@alfalab/core-components-select';
</div>
</Preview>

#### OptionShape вместо ключей для выбранных пунктов

Иногда может быть удобнее использовать в качестве выбранных значений не ключи, а сами объекты.
В этом случае просто перевайте их через свойство `selected`.

<Preview>
<div style={{ height: 180, width: 300 }}>
{React.createElement(() => {
const [selected, setSelected] = React.useState([options[8], options[9]]);
const handleChange = ({ selectedMultiple }) => {
setSelected(selectedMultiple);
};
return (
<Select
block={true}
options={options}
placeholder='Выберите элемент'
label='controlled'
multiple={true}
onChange={handleChange}
selected={selected}
/>
);
})}
</div>
</Preview>

### Использование в форме

Чтобы использовать селект внутри формы - следует указать атрибут `name`
Expand Down
2 changes: 1 addition & 1 deletion packages/select/src/typings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export type BaseSelectProps = {
/**
* Список value выбранных пунктов (controlled-селект)
*/
selected?: string[] | string | null;
selected?: Array<string | OptionShape> | string | OptionShape | null;

/**
* Рендерит нативный селект вместо выпадающего меню. (на десктопе использовать только с multiple=false)
Expand Down
19 changes: 19 additions & 0 deletions packages/select/src/utils.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,23 @@ describe('processOptions', () => {
expect(processOptions(options, ['non-existing key']).selectedOptions).toEqual([]);
expect(processOptions(groups, ['non-existing key']).selectedOptions).toEqual([]);
});

it('should return selected options by list of objects', () => {
expect(processOptions(options, [options[0], options[6]]).selectedOptions).toEqual([
options[0],
options[6],
]);

expect(processOptions(groups, [options[0], options[6]]).selectedOptions).toEqual([
options[0],
options[6],
]);
});

it('should return selected options even if passed objects not in options', () => {
expect(processOptions(options, [options[1], options[2]]).selectedOptions).toEqual([
options[1],
options[2],
]);
});
});
19 changes: 12 additions & 7 deletions packages/select/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { OptionShape, GroupShape, BaseSelectProps } from './typings';
export const isGroup = (item: OptionShape | GroupShape): item is GroupShape =>
Object.prototype.hasOwnProperty.call(item, 'options');

export const isOptionShape = (item: OptionShape | string | null): item is OptionShape =>
item !== null && Object.prototype.hasOwnProperty.call(item, 'key');

export const joinOptions = ({
selected,
selectedMultiple,
Expand All @@ -30,20 +33,22 @@ export const joinOptions = ({
// За один проход делает список пунктов меню плоским и находит выбранные пункты по ключу
export function processOptions(
options: BaseSelectProps['options'],
selectedKeys: BaseSelectProps['selected'] = [],
selected: BaseSelectProps['selected'] = [],
) {
const flatOptions: OptionShape[] = [];
const selectedOptions: OptionShape[] = [];

const selected = (option: OptionShape) =>
Array.isArray(selectedKeys)
? selectedKeys.includes(option.key)
: selectedKeys === option.key;
const selectedArray = Array.isArray(selected) ? selected : [selected];
const selectedOptions = selectedArray.filter(isOptionShape);
const selectedKeys = selectedArray.filter(
(option): option is string => typeof option === 'string',
);

const isSelected = (option: OptionShape) => selectedKeys.includes(option.key);

const process = (option: OptionShape) => {
flatOptions.push(option);

if (selected(option)) {
if (isSelected(option)) {
selectedOptions.push(option);
}
};
Expand Down

0 comments on commit a16f47a

Please sign in to comment.