import { map, isNil } from 'lodash'; import React, { useState } from 'react'; import { Meta } from '@storybook/react'; import SingleSelect from './SingleSelect'; import DangerIcon from '../Icon/DangerIcon/DangerIcon'; import PlusIcon from '../Icon/PlusIcon/PlusIcon'; import SuccessIcon from '../Icon/SuccessIcon/SuccessIcon'; import InfoIcon from '../Icon/InfoIcon/InfoIcon'; //πŸ‘‡ Provide Storybook with the component name, 'section', any subcomponents and a description export default { title: 'Controls/SingleSelect', component: SingleSelect, subcomponents: { 'SingleSelect.Placeholder': SingleSelect.Placeholder, 'SingleSelect.Option': SingleSelect.Option, 'SingleSelect.Option.Selected': SingleSelect.Option.Selected, 'SingleSelect.OptionGroup': SingleSelect.OptionGroup, }, parameters: { docs: { description: { component: SingleSelect.peek.description, }, }, }, } as Meta; //πŸ‘‡ Destructure any child components that we will need const { Option, OptionGroup } = SingleSelect; //πŸ‘‡ Add a key prop to each element of the array function addKeys(children) { return map(children, (child, index) => ({ ...child, key: index })); } //πŸ‘‡ Create a β€œtemplate” of how args map to rendering const Template: any = (args) => { const [selectedIndex, setSelectedIndex] = useState(null); const [selectedOptionName, setSelectedOptionName] = useState( null ); const handleSelect = (optionIndex: number | null) => { const name = !isNil(optionIndex) ? args.children[optionIndex].props.name : null; setSelectedIndex(optionIndex); setSelectedOptionName(name); }; return (
handleSelect(e)}> {!isNil(selectedIndex) && (
Selected Index: {JSON.stringify(selectedIndex)}
)} {selectedOptionName && (

Selected Option Name: {JSON.stringify(selectedOptionName)}

)}
); }; /** Basic */ export const Basic = Template.bind({}); Basic.args = { Placeholder: 'Select Color', children: addKeys([ , , , ]), }; /** Named Options */ export const NamedOptions = Template.bind({}); NamedOptions.args = { ...Basic.args, children: addKeys([ , , , ]), }; NamedOptions.parameters = { docs: { description: { story: `Use named options when you need to display different values within the dropdown and elsewhere on the screen after the user makes a selection. `, }, }, }; /** Formatted Options */ const OptionCols = ({ col1, col2 }: { col1: string; col2: string }) => (
{col1}
{col2}
); export const FormattedOptions = Template.bind({}); FormattedOptions.args = { ...Basic.args, children: addKeys([ , ]), }; FormattedOptions.parameters = { docs: { description: { story: `Use multiple columns of data in your dropdown when additional information is needed to make a selection. `, }, }, }; /** Grouped Options */ export const GroupedOptions = Template.bind({}); GroupedOptions.args = { ...Basic.args, children: addKeys([ Screen , Print , ]), }; GroupedOptions.parameters = { docs: { description: { story: `Grouped options allows you to have sections within your dropdown. Use this to help frame users' understanding of the options. `, }, }, }; /** Disabled Options */ export const DisabledOptions = Template.bind({}); DisabledOptions.args = { ...Basic.args, children: addKeys([ , , , ]), }; DisabledOptions.parameters = { docs: { description: { story: `Apply \`isDisabled\` to dropdown options that aren't currently available. `, }, }, }; /** Disabled Select */ export const DisabledSelect = Template.bind({}); DisabledSelect.args = { ...Basic.args, isDisabled: true, }; DisabledSelect.parameters = { docs: { description: { story: `Apply \`isDisabled\` to the dropdown if none of the options are currently available. `, }, }, }; /** No Unselect */ export const NoUnselect = Template.bind({}); NoUnselect.args = { ...Basic.args, hasReset: false, }; NoUnselect.parameters = { docs: { description: { story: `This removes the default state, displayed as the \`Placeholder\`. Use \`hasReset="false"\` to prevent users from deselecting a setting. `, }, }, }; /** Max Menu Height */ export const MaxMenuHeight = Template.bind({}); MaxMenuHeight.args = { ...Basic.args, maxMenuHeight: '7em', children: addKeys([ , , , , , , , , , , , , , , , ]), }; MaxMenuHeight.parameters = { docs: { description: { story: `Provide a fixed menu height with the \`maxMenuHeight\` prop. It will allow users to scroll through the options within a fixed height. `, }, }, }; /** Rich Content */ export const RichContent = Template.bind({}); RichContent.args = { ...Basic.args, Placeholder: ( <> Add Color ), children: addKeys([ , , , ]), }; RichContent.parameters = { docs: { description: { story: `You can include rich content in the dropdown. Use icons or other rich content where an image will help users make a selection: a company logo near the company name, for example. `, }, }, }; /** No Selection Highlighting */ export const NoSelectionHighlighting = Template.bind({}); NoSelectionHighlighting.args = { ...Basic.args, isSelectionHighlighted: false, }; NoSelectionHighlighting.parameters = { docs: { description: { story: `Use \`isSelectionHighlighted="false"\` when the dropdown defaults to null selections such as 'All' or 'Any'. The grey outline indicates that this selection does not need users' attention. `, }, }, }; /** Array Options */ export const ArrayOptions = Template.bind({}); ArrayOptions.args = { Placeholder: 'Select a Number', Option: addKeys([, , ]), }; ArrayOptions.parameters = { docs: { description: { story: `If needed, you can pass your dropdown option data as an array. `, }, }, }; /** Stateless */ export const Stateless = Template.bind({}); Stateless.args = { ...Basic.args, selectedIndex: 1, DropMenu: { focusedIndex: 2, isExpanded: true }, style: { minHeight: 220 }, children: addKeys([ Preferred , , , , ]), }; Stateless.parameters = { docs: { description: { story: ` This example shows the various states available in \`SingleSelect\`. `, }, }, }; /** Invisible */ export const Invisible = Template.bind({}); Invisible.args = { ...Basic.args, isInvisible: true, }; Invisible.parameters = { docs: { description: { story: `Setting the \`IsInvisible\` prop to 'true' removes the dropdown border. The lack of a border gives the dropdown a lighter visual weight within a data-intense layout. `, }, }, }; /** Invisible and Disabled */ export const InvisibleAndDisabled = Template.bind({}); InvisibleAndDisabled.args = { ...Basic.args, isInvisible: true, isDisabled: true, }; InvisibleAndDisabled.parameters = { docs: { description: { story: `Setting the \`IsInvisible\` prop to 'true' removes the dropdown border, and \`isDisabled\` indicates that the dropdown option isn't currently available. `, }, }, }; /** With Title */ export const Title = Template.bind({}); Title.args = { ...Basic.args, Title: 'Sample Title', }; Title.parameters = { docs: { description: { story: `Setting the \`Title\` prop to 'Sample Title' adds a title to the single select.`, }, }, };