import React, { useState } from 'react'; import createClass from 'create-react-class'; import _, { map } from 'lodash'; import { Meta, Story } from '@storybook/react'; import Resizer from '../Resizer/Resizer'; import SearchableMultiSelect, { ISearchableMultiSelectProps, } from './SearchableMultiSelect'; import Selection from '../Selection/Selection'; //👇 Provide Storybook with the component name, 'section', any subcomponents and a description export default { title: 'Controls/SearchableMultiSelect', component: SearchableMultiSelect, subcomponents: { 'SearchableMultiSelect.SelectionOption': SearchableMultiSelect.Option.Selection, 'SearchableMultiSelect.Option.Selected': SearchableMultiSelect.Option.Selected, 'SearchableMultiSelect.OptionGroup': SearchableMultiSelect.OptionGroup, 'SearchableMultiSelect.SearchFieldComponent': SearchableMultiSelect.SearchField, 'SearchableMultiSelect.Option': SearchableMultiSelect.Option, }, parameters: { docs: { description: { component: SearchableMultiSelect.peek.description, }, }, }, args: SearchableMultiSelect.defaultProps, } as Meta; //👇 Destructure any child components that we will need const { Option } = SearchableMultiSelect; //👇 Add a key prop to each element of the array function addKeys(children: any) { return map(children, (child, index) => ({ ...child, key: index })); } /* Basic */ export const Basic: Story = (args) => { return ; }; Basic.args = { children: addKeys([ , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ]), }; /* Props */ export const Props: Story = (args) => { const { Option } = SearchableMultiSelect; return ( {(width) => { const responsiveMode = width >= 768 ? 'large' : 'small'; return (
Loading
Disabled
Custom option selections
No remove all option
); }}
); }; /* Asynchronous */ export const Asynchronous: Story = (args) => { const { Option } = SearchableMultiSelect; 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' }, }; const Component = createClass({ getInitialState() { return { selectedIds: [], // aka our full set of selections regardless of currently search visibleIds: [], // aka current search results isLoading: false, }; }, componentDidMount() { this.handleSearch(''); }, handleSearch(searchText: string) { this.setState({ isLoading: true }); // Fake an API call setTimeout(() => { const visibleIds = _.reduce( allData, (acc: any[], { name }: { name: string }, id: string) => { return _.includes(name.toLowerCase(), searchText.toLowerCase()) ? acc.concat(id) : acc; }, [] ); this.setState({ visibleIds, isLoading: false, }); }, 750); }, handleRemove({ props: { callbackId }, }: { props: { callbackId: string; }; }) { this.setState({ selectedIds: _.without(this.state.selectedIds, callbackId), }); }, handleSelect( index: number, { props: { callbackId }, }: { props: { callbackId: string; }; } ) { this.setState({ selectedIds: _.xor(this.state.selectedIds, [callbackId]), }); }, render() { const { isLoading, visibleIds, selectedIds } = this.state; // Calculate selected indices based on selected ids const selectedIndices = _.reduce( visibleIds, (acc: any[], id: string, index: number) => { return _.includes(selectedIds, id) ? acc.concat(index) : acc; }, [] ); return (
{_.map(visibleIds, (id) => ( ))} {!_.isEmpty(selectedIds) ? ( {_.map(selectedIds, (id) => ( ))} ) : null}
); }, }); return ; }; Asynchronous.args = { ...Basic.args, }; /* Grouped Options */ export const GroupedOptions: Story = (args) => { const { Option, OptionGroup } = SearchableMultiSelect; return ( Northeast Southeast Midwest Southwest West ); }; /* Custom Selection Label */ export const CustomSelectionLabel: Story = ( args ) => { const { Option, SelectionLabel } = SearchableMultiSelect; return ( Selected States ); }; /* Select All */ export const SelectAll: Story = (args) => { const { Option } = SearchableMultiSelect; return (
{(width) => { const responsiveMode = width >= 768 ? 'large' : 'small'; return ( ); }}
); }; /* Formatted Options */ export const FormattedOptions: Story = (args) => { // eslint-disable-next-line react/prop-types interface Props extends React.HTMLProps { match?: any; } function P({ children, ...rest }: Props) { return

{children}

; } const OptionCols: any = ({ col1, col2, textMatch, }: { col1: string; col2: string; textMatch: string; }) => (

{col1}

{col2}

); const optionFilter = ( searchText: string, { filterText, }: { filterText: string; } ) => { if (filterText) { return new RegExp(_.escapeRegExp(searchText), 'i').test(filterText); } return true; }; return (
{({ searchText }: { searchText: string }) => ( )} {({ searchText }: { searchText: string }) => ( )} {({ searchText }: { searchText: string }) => ( )}
); }; FormattedOptions.args = { ...Basic.args, }; /* Invalid */ export const Invalid: Story = (args) => { const { Option } = SearchableMultiSelect; const [selectedLength, setSelectedLength] = useState(0); const handleChange = (option: string, event: any) => { let count = selectedLength; if (typeof event.props.children === 'string') { count--; } else { event.props.children.props.isSelected ? count-- : count++; } setSelectedLength(count); }; const handleRemoveAll = (option: string, event: any) => { setSelectedLength(0); }; return ( 1 ? null : 'Please select at least two options'} > ); };