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;
}) => (
);
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.
`,
},
},
};