UNPKG

@wix/design-system

Version:

@wix/design-system

426 lines (367 loc) 12.7 kB
## Feature Examples ### Size - description: <p>Adjust the component size using the <code>size</code> prop. It supports 3 sizes:</p><li><code>large</code> is best for onboarding flows, where input needs emphasis.</li><li><code>medium</code> (default) – use for most cases.</li><li><code>small</code> is appropriate for dense and narrow layouts.</li> - example: ```jsx () => { const options = [ { id: 1, value: 'tag 1' }, { id: 2, value: 'tag 2' }, { id: 3, value: 'tag 3' }, ]; const renderMultiSelect = ({ size, tagSize }) => { const [tags, setTags] = React.useState([ { size: tagSize, id: '1', label: 'tag 1', }, { size: tagSize, id: '2', label: 'tag 2', }, ]); const handleOnSelect = tag => setTags([...tags, { id: tag.id, label: tag.value, size: tagSize }]); const handleOnRemoveTag = tagId => setTags(tags.filter(currTag => currTag.id !== tagId)); return ( <MultiSelect size={size} options={options} tags={tags} onSelect={handleOnSelect} onRemoveTag={handleOnRemoveTag} /> ); }; return ( <StorybookComponents.Stack flexDirection="column"> <FormField label="Large"> {renderMultiSelect({ size: 'large', tagSize: 'medium' })} </FormField> <FormField label="Medium"> {renderMultiSelect({ size: 'medium', tagSize: 'small' })} </FormField> <FormField label="Small"> {renderMultiSelect({ size: 'small', tagSize: 'tiny' })} </FormField> </StorybookComponents.Stack> ); }; ``` ### Border - description: <p>Style the component using the <code>border</code> prop. It supports 4 styles:</p><li>For forms and most common cases, use <code>default</code>.</li><li>When component is used to filter data, use <code>round</code>.</li><li>Use <code>bottomLine</code> to create an editable, underlined title field.</li><li>When a component provides its own hover and focus styles, such as a table or spreadsheet cells, use <code>none</code>.</li> - example: ```jsx () => { const options = [ { value: 'Option 1', id: '1' }, { value: 'Option 2', id: '2' }, { value: 'Option 3', id: '3' }, { value: 'Option 4', id: '4' }, { value: 'Option 5', id: '5' }, ]; return ( <StorybookComponents.Stack flexDirection="column"> <MultiSelect border="standard" placeholder="Standard" options={options} mode="select" /> <MultiSelect border="round" placeholder="Round" options={options} mode="select" /> <MultiSelect border="bottomLine" placeholder="Bottom line" options={options} mode="select" /> <MultiSelect border="none" placeholder="None" options={options} mode="select" /> </StorybookComponents.Stack> ); }; ``` ### Status - description: <p>Control the component status using a <code>status</code> prop. It supports 3 states:</p><li><code>error</code> demonstrates that a required input is missing something or the entry was invalid.</li><li><code>warning</code> highlights a value that might have a significant impact to a user.</li><li><code>loading</code> shows when a value is being uploaded to the server.</li> - example: ```jsx () => { const options = [ { value: 'Option 1', id: '1' }, { value: 'Option 2', id: '2' }, { value: 'Option 3', id: '3' }, { value: 'Option 4', id: '4' }, { value: 'Option 5', id: '5' }, ]; return ( <StorybookComponents.Stack flexDirection="column"> <MultiSelect status="error" placeholder="Error" options={options} /> <MultiSelect status="warning" placeholder="Warning" options={options} /> <MultiSelect status="loading" placeholder="Loading" options={options} /> </StorybookComponents.Stack> ); }; ``` ### Status message - description: <p>Add text that explains the status or what action the user should take with the <code>statusMessage</code> prop.</p><p></p><p>Showing the status message inline, directly below the component is preferred in all default cases.</p><li>To add an accessible inline message, wrap the component in a <code><FormField/></code> and add the <code>statusMessage</code>.</li><li>To add a status message in a tooltip that requires users to hover on the icon, use the <code>statusMessage</code> prop. Control tooltip placement with <code>tooltipPlacement</code> prop.</li><p></p><p>View more inline status message examples in <code><FormField/></code>.</p> - example: ```jsx () => { const options = [ { value: 'Option 1', id: '1' }, { value: 'Option 2', id: '2' }, { value: 'Option 3', id: '3' }, { value: 'Option 4', id: '4' }, { value: 'Option 5', id: '5' }, ]; return ( <StorybookComponents.Stack flexDirection="column"> <StorybookComponents.Stack flexDirection="column" gap="12px"> <Text secondary>For all default cases:</Text> <FormField status="error" statusMessage="This is an error message."> <MultiSelect placeholder="See message below" options={options} /> </FormField> </StorybookComponents.Stack> <StorybookComponents.Stack flexDirection="column" gap="12px"> <Text secondary>For narrow layouts only:</Text> <MultiSelect status="error" placeholder="Hover on status icon" statusMessage="This is an error message." options={options} /> </StorybookComponents.Stack> </StorybookComponents.Stack> ); }; ``` ### Read-only and disabled - description: <p>Multi select can also be made read-only or disabled entirely.</p><li><code>readOnly</code> disables adding or editing, but allows the user to copy the current value. Use it to display URLs, code, etc.</li><li><code>disabled</code> removes all interactions and creates a disabled component state. Use it to highlight functions that are unavailable.</li> - example: ```jsx () => { const options = [ { value: 'Option 1', id: '1' }, { value: 'Option 2', id: '2' }, { value: 'Option 3', id: '3' }, { value: 'Option 4', id: '4' }, { value: 'Option 5', id: '5' }, ]; return ( <StorybookComponents.Stack flexDirection="column"> <MultiSelect value="Read Only" readOnly /> <MultiSelect placeholder="Disabled" mode="select" options={options} disabled /> </StorybookComponents.Stack> ); }; ``` ### Action - description: <p>Encourage user engagement by displaying the call to action. To add a <code><TextButton/></code>, <a href="https://www.wix-style-react.com/storybook/?path=/story/components-actions--textbutton"></a>use the <code>customSuffix</code> property.</p> - example: ```jsx () => { const [tags, setTags] = React.useState([]); const handleOnSelect = tag => setTags([...tags, { id: tag.id, label: tag.value }]); const handleOnRemoveTag = tagId => setTags(tags.filter(currTag => currTag.id !== tagId)); return ( <MultiSelect tags={tags} options={[ { id: '1', value: 'tag 1' }, { id: '2', value: 'tag 2' }, { id: '3', value: 'tag 3' }, ]} customSuffix={ <Box> <TextButton prefixIcon={<Icons.Add />}>Add Tag</TextButton> </Box> } onSelect={handleOnSelect} onRemoveTag={handleOnRemoveTag} /> ); }; ``` ### Select mode - description: <p>Allow users to select only options that are listed with <code>mode</code> prop.</p> - example: ```jsx () => { const [tags, setTags] = React.useState([]); const handleOnSelect = tag => setTags([...tags, { id: tag.id, label: tag.value }]); const handleOnRemoveTag = tagId => setTags(tags.filter(currTag => currTag.id !== tagId)); return ( <MultiSelect tags={tags} options={[ { id: '1', value: 'tag 1' }, { id: '2', value: 'tag 2' }, { id: '3', value: 'tag 3' }, ]} mode="select" placeholder="Select tags from a list" onSelect={handleOnSelect} onRemoveTag={handleOnRemoveTag} /> ); }; ``` ### Manual input - description: <p>Allow users to enter their own tags using the keyboard with <code>onManuallyInput</code> property.</p> - example: ```jsx () => { const [tags, setTags] = React.useState([]); const handleManualInput = tag => setTags([...tags, { id: Math.random(), label: tag[0] }]); const handleOnRemoveTag = tagId => setTags(tags.filter(currTag => currTag.id !== tagId)); return ( <MultiSelect tags={tags} placeholder="Type custom tags and separate them with the Enter key" onManuallyInput={handleManualInput} onRemoveTag={handleOnRemoveTag} /> ); }; ``` ### Predicate - description: <p>Build autocomplete features using the <code>predicate</code> property.</p> - example: ```jsx () => { const [value, setValue] = React.useState(''); const [tags, setTags] = React.useState([]); const options = [ { value: 'Alabama', id: 'AL' }, { value: 'California', id: 'CA' }, { value: 'North Carolina', id: 'NC' }, { value: 'Colorado', id: 'CO' }, { value: 'Connecticut', id: 'CT' }, ]; const handleOnChange = event => setValue(event.target.value); const predicate = option => option.value && option.value.toLowerCase().includes(value.toLowerCase()); const handleOnSelect = tag => setTags([...tags, { id: tag.id, label: tag.value }]); const handleOnRemoveTag = tagId => setTags(tags.filter(currTag => currTag.id !== tagId)); return ( <MultiSelect predicate={predicate} tags={tags} value={value} options={options} onChange={handleOnChange} placeholder="Start typing a state to find a match" onSelect={handleOnSelect} onRemoveTag={handleOnRemoveTag} /> ); }; ``` ### Reorder - description: <p>Use the <code>onReorder</code> property to allow users to change the order in which keywords are displayed.</p> - example: ```jsx () => { const [tags, setTags] = React.useState([ { id: 1, label: 'One' }, { id: 2, label: 'Two' }, { id: 3, label: 'Three' }, ]); const options = [ { id: 1, value: 'One' }, { id: 2, value: 'Two' }, { id: 3, value: 'Three' }, ]; const handleOnSelect = tag => setTags([...tags, { id: tag.id, label: tag.value }]); const handleOnRemoveTag = tagId => setTags(tags.filter(currTag => currTag.id !== tagId)); return ( <MultiSelect tags={tags} options={options} onReorder={({ addedIndex, removedIndex }) => { const nextTags = tags.slice(); nextTags.splice(addedIndex, 0, ...nextTags.splice(removedIndex, 1)); setTags(nextTags); }} onSelect={handleOnSelect} onRemoveTag={handleOnRemoveTag} /> ); }; ``` ## Common Use Case Examples ### Enter contact emails - description: <p>Multiselect input can be useful for entering contacts or emails.</p><p></p><p>If combined with advanced list item props, multiselect can provide explicit information, therefore, making multiple keyboard entries easier.</p> - example: ```jsx () => { const [value, setValue] = React.useState(''); const [tags, setTags] = React.useState([]); const contacts = [ { name: 'River Watts', email: 'riverw@wix.com', id: 1 }, { name: 'Jesse Neimus', email: 'jessen@wix.com', id: 2 }, { name: 'Morgan James', email: 'morganj@wix.com', id: 3 }, { name: 'Reese Whiteman', email: 'reesew@wix.com', id: 4 }, ]; const options = contacts.map(contact => ({ ...contact, ...listItemSelectBuilder({ prefix: ( <Avatar size="size30" imgProps={{ src: `AvatarExample${contact.id}.jpg` }} /> ), id: contact.id, title: contact.name, subtitle: contact.email, }), })); const handleOnSelect = ({ name, email, id }) => setTags([...tags, { id, label: name ? `${email} (${name})` : email }]); const handleOnRemoveTag = tagId => setTags(tags.filter(currTag => currTag.id !== tagId)); const handleOnChange = event => setValue(event.target.value); const predicate = option => (option.name + option.email).toLowerCase().includes(value.toLowerCase()); return ( <MultiSelect value={value} options={options} tags={tags} onChange={handleOnChange} onSelect={handleOnSelect} onRemoveTag={handleOnRemoveTag} placeholder="Start typing a name to find a match" predicate={predicate} /> ); }; ```