From f6912b5a48dcd1ab7650e55f392428b838d7d7b6 Mon Sep 17 00:00:00 2001 From: Niclas Liimatainen Date: Fri, 5 Jun 2020 12:54:06 +0300 Subject: [PATCH] Add support for controlling selected option(s) --- .../components/dropdown/Dropdown.stories.tsx | 47 ++++++++++++++++++- .../src/components/dropdown/Dropdown.tsx | 9 ++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/packages/react/src/components/dropdown/Dropdown.stories.tsx b/packages/react/src/components/dropdown/Dropdown.stories.tsx index 6d30d3e0dd..381ef6d9fa 100644 --- a/packages/react/src/components/dropdown/Dropdown.stories.tsx +++ b/packages/react/src/components/dropdown/Dropdown.stories.tsx @@ -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' }, @@ -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 ( + <> + + {['Dropdown 1', 'Dropdown 2'].map((label) => ( + + ))} + + {['Multiselect 1', 'Multiselect 2'].map((label) => ( + + ))} + + ); +}; + +Controlled.story = { + name: 'With controlled state', +}; + Multiselect.story = { name: 'With multiselect', }; diff --git a/packages/react/src/components/dropdown/Dropdown.tsx b/packages/react/src/components/dropdown/Dropdown.tsx index 797a604542..8cdf62024f 100644 --- a/packages/react/src/components/dropdown/Dropdown.tsx +++ b/packages/react/src/components/dropdown/Dropdown.tsx @@ -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 */ @@ -171,6 +175,7 @@ const Dropdown: FC = ({ options = [], placeholder = '', required, + selectedOption, style, toggleButtonId, visibleOptions = 5, @@ -188,6 +193,7 @@ const Dropdown: FC = ({ // init multi-select const { getDropdownProps, addSelectedItem, removeSelectedItem, selectedItems } = useMultipleSelection({ initialSelectedItems: defaultValues, + ...(multiselect && selectedOption !== undefined && { selectedItems: (selectedOption as OptionType[]) ?? [] }), onSelectedItemsChange: ({ selectedItems: _selectedItems }) => multiselect && onChange(_selectedItems), }); @@ -233,6 +239,9 @@ const Dropdown: FC = ({ 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, };