Skip to content

Commit

Permalink
Merge pull request #163 from City-of-Helsinki/feature/controlled-drop…
Browse files Browse the repository at this point in the history
…down

[Feature] - Dropdown - Add support for controlling selected option(s)
  • Loading branch information
niglu1 authored Jun 5, 2020
2 parents b480bba + f6912b5 commit fad0676
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 1 deletion.
47 changes: 46 additions & 1 deletion packages/react/src/components/dropdown/Dropdown.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react';
import React, { useState } from 'react';
import { boolean, number, text, withKnobs } from '@storybook/addon-knobs';

import Dropdown from './Dropdown';
import Button from '../button/Button';

const options = [
{ label: 'Plutonium' },
Expand Down Expand Up @@ -76,6 +77,50 @@ export const Multiselect = () => (
/>
);

export const Controlled = () => {
const [selectedItem, setSelectedItem] = useState(null);
const [multiselectSelectedItem, setMultiselectSelectedItem] = useState(null);

const handleSelectedItemChange = (item) => setSelectedItem(item);
const handleMultiselectSelectedItemChange = (item) => setMultiselectSelectedItem(item);

return (
<>
<Button onClick={() => setSelectedItem(null)}>Reset</Button>
{['Dropdown 1', 'Dropdown 2'].map((label) => (
<Dropdown
key={label}
options={options}
placeholder="Placeholder"
label={label}
onChange={handleSelectedItemChange}
selectedOption={selectedItem}
style={{ marginTop: 'var(--spacing-s)' }}
/>
))}
<Button onClick={() => setMultiselectSelectedItem(null)} style={{ marginTop: 'var(--spacing-xl)' }}>
Reset multiselect
</Button>
{['Multiselect 1', 'Multiselect 2'].map((label) => (
<Dropdown
key={label}
options={options}
placeholder="Placeholder"
label={label}
multiselect
onChange={handleMultiselectSelectedItemChange}
selectedOption={multiselectSelectedItem}
style={{ marginTop: 'var(--spacing-s)' }}
/>
))}
</>
);
};

Controlled.story = {
name: 'With controlled state',
};

Multiselect.story = {
name: 'With multiselect',
};
Expand Down
9 changes: 9 additions & 0 deletions packages/react/src/components/dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ export type DropdownProps = {
* If `true`, the label is displayed as required
*/
required?: boolean;
/**
* The option(s) that should be selected
*/
selectedOption?: OptionType | OptionType[];
/**
* Override or extend the root styles applied to the component
*/
Expand Down Expand Up @@ -171,6 +175,7 @@ const Dropdown: FC<DropdownProps> = ({
options = [],
placeholder = '',
required,
selectedOption,
style,
toggleButtonId,
visibleOptions = 5,
Expand All @@ -188,6 +193,7 @@ const Dropdown: FC<DropdownProps> = ({
// init multi-select
const { getDropdownProps, addSelectedItem, removeSelectedItem, selectedItems } = useMultipleSelection<OptionType>({
initialSelectedItems: defaultValues,
...(multiselect && selectedOption !== undefined && { selectedItems: (selectedOption as OptionType[]) ?? [] }),
onSelectedItemsChange: ({ selectedItems: _selectedItems }) => multiselect && onChange(_selectedItems),
});

Expand Down Expand Up @@ -233,6 +239,9 @@ const Dropdown: FC<DropdownProps> = ({
onSelectedItemChange: ({ selectedItem }) => !multiselect && onChange(selectedItem),
// selected items are handled by stateReducer when multiselect is enabled
...(multiselect && { selectedItem: null }),
// a value for selectedOption indicates that the dropdown should be controlled
// don't set selectedItem if it's not, so that downshift can control the selected item(s)
...(!multiselect && selectedOption !== undefined && { selectedItem: selectedOption }),
stateReducer,
toggleButtonId,
};
Expand Down

0 comments on commit fad0676

Please sign in to comment.