import { includes, map, reduce, indexOf, constant, escapeRegExp, get, } from 'lodash'; import React, { useState } from 'react'; import { Meta } from '@storybook/react'; import SearchableSingleSelect from './SearchableSingleSelect'; import Underline from '../Underline/Underline'; //πŸ‘‡ Provide Storybook with the component name, 'section', any subcomponents and a description export default { title: 'Controls/SearchableSingleSelect', component: SearchableSingleSelect, subcomponents: { 'SearchableSingleSelect.Placeholder': SearchableSingleSelect.SearchField, 'SearchableSingleSelect.Option': SearchableSingleSelect.Option, 'SearchableSingleSelect.Option.Selected': SearchableSingleSelect.Option.Selected, 'SearchableSingleSelect.OptionGroup': SearchableSingleSelect.OptionGroup, 'SearchableSingleSelect.SearchField': SearchableSingleSelect.SearchField, }, parameters: { docs: { description: { component: SearchableSingleSelect.peek.description, }, }, }, } as Meta; //πŸ‘‡ Destructure any child components that we will need const { Option, OptionGroup } = SearchableSingleSelect; //πŸ‘‡ Add a key prop to each child element of the array function addKeys(children: any) { return map(children, (child, index) => ({ ...child, key: index })); } //πŸ‘‡ Create a β€œtemplate” of how args map to rendering const Template: any = (args) => { return (
); }; //πŸ‘‡ Each story then reuses that template /** Basic */ export const Basic = Template.bind({}); Basic.args = { SearchField: { placeholder: 'Search State' }, children: addKeys([ , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ]), }; /** Props */ export const Props = (args) => { return (
Loading
Disabled
); }; Props.args = { ...Basic.args, SearchField: { placeholder: '' }, }; Props.parameters = { docs: { description: { story: `Apply \`isLoading\` to the dropdown when it is loading, and apply \`isDisabled\` to the dropdown if none of the options are currently available. `, }, }, }; /** Asynchronous */ const allData: any = { 100: { name: 'Rita Daniel' }, 101: { name: 'Meghan Mcgowan' }, 102: { name: 'Latisha Kent' }, 103: { name: 'Jeannine Horton' }, 104: { name: 'Noreen Joyner' }, 105: { name: 'Angelique Head' }, 106: { name: 'Kim Salinas' }, 107: { name: 'Alexis Small' }, 108: { name: 'Fernandez Singleton' }, 109: { name: 'Jacqueline Alvarado' }, 110: { name: 'Cornelia Roman' }, 111: { name: 'John Gonzales' }, 112: { name: 'Mcleod Hodge' }, 113: { name: 'Fry Barrera' }, 114: { name: 'Jannie Compton' }, 115: { name: 'June Odom' }, 116: { name: 'Rose Foster' }, 117: { name: 'Kathryn Prince' }, 118: { name: 'Hebert Bowman' }, 119: { name: 'Shawn Burgess' }, }; export const Asynchronous = (args) => { const [selectedId, setSelectedId] = useState(null); // current selection const [visibleIds, setVisibleIds] = useState([]); // aka current search results const [isLoading, setIsLoading] = useState(false); const handleSearch = (searchText) => { setIsLoading(true); // Fake an API call setTimeout(() => { const searchResults = reduce( allData, (acc: any[], { name }: { name: string }, id: string) => { return includes(name.toLowerCase(), searchText.toLowerCase()) ? acc.concat(id) : acc; }, [] ); setIsLoading(false); setVisibleIds(searchResults); }); }; const handleSelect = (index: string, event: any) => { const optionsId = get(event, 'props.callbackId', null); setSelectedId(optionsId); }; const selectedIndex = indexOf(visibleIds, selectedId) === -1 ? null : indexOf(visibleIds, selectedId); return (
{map(visibleIds, (id) => ( ))}
); }; /** Grouped Options */ export const GroupedOptions = Template.bind({}); GroupedOptions.args = { children: addKeys([ Northeast , Southeast , Midwest , Southwest , West , , , ]), }; 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. `, }, }, }; /** Selected Option */ export const SelectedOption = Template.bind({}); SelectedOption.args = { ...Basic.args, SearchField: { placeholder: 'Search Color', }, children: addKeys([ , , , ]), }; /** Invalid Option */ export const InvalidOption = () => { const [selectedIndex, setSelectedIndex] = useState(null); const handleSelect = (optionIndex: number | null) => { setSelectedIndex(optionIndex); }; return ( ); }; /** Formatted Options */ const OptionCols = ({ col1, col2, col3, textMatch, }: { col1: string; col2: string; col3: string; textMatch?: string | undefined; }) => (
{col1}
{col2}
{col3}
); const optionFilter = ( searchText: string, { filterText }: { filterText: string } ) => { if (filterText) { return new RegExp(escapeRegExp(searchText), 'i').test(filterText); } return true; }; export const FormattedOptions = Template.bind({}); FormattedOptions.args = { ...Basic.args, SearchField: { placeholder: 'Search Options', }, optionFilter, children: addKeys([ , ]), }; FormattedOptions.parameters = { docs: { description: { story: `Use multiple columns of data in your dropdown when additional information is needed to make a selection. `, }, }, };