Add support for sections to Select (#34012)
Updates the Select component to accept a set of sections with options as opposed to just a flat list of options. --------- Signed-off-by: James Brooks <jamesbrooks@spotify.com>
This commit is contained in:
@@ -40,6 +40,33 @@ const skills = [
|
||||
{ value: 'swift', label: 'Swift' },
|
||||
];
|
||||
|
||||
const sectionedFonts = [
|
||||
{
|
||||
title: 'Serif Fonts',
|
||||
options: [
|
||||
{ value: 'times', label: 'Times New Roman' },
|
||||
{ value: 'georgia', label: 'Georgia' },
|
||||
{ value: 'garamond', label: 'Garamond' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Sans-Serif Fonts',
|
||||
options: [
|
||||
{ value: 'arial', label: 'Arial' },
|
||||
{ value: 'helvetica', label: 'Helvetica' },
|
||||
{ value: 'verdana', label: 'Verdana' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Monospace Fonts',
|
||||
options: [
|
||||
{ value: 'courier', label: 'Courier New' },
|
||||
{ value: 'consolas', label: 'Consolas' },
|
||||
{ value: 'fira', label: 'Fira Code' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const Preview = () => (
|
||||
<Select
|
||||
label="Font Family"
|
||||
@@ -148,3 +175,23 @@ export const SearchableMultiple = () => (
|
||||
style={{ width: 300 }}
|
||||
/>
|
||||
);
|
||||
|
||||
export const WithSections = () => (
|
||||
<Select
|
||||
label="Font Family"
|
||||
options={sectionedFonts}
|
||||
name="font"
|
||||
style={{ width: 300 }}
|
||||
/>
|
||||
);
|
||||
|
||||
export const SearchableWithSections = () => (
|
||||
<Select
|
||||
label="Font Family"
|
||||
searchable
|
||||
searchPlaceholder="Search fonts..."
|
||||
options={sectionedFonts}
|
||||
name="font"
|
||||
style={{ width: 300 }}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -12,8 +12,14 @@ import {
|
||||
Searchable,
|
||||
MultipleSelection,
|
||||
SearchableMultiple,
|
||||
WithSections,
|
||||
SearchableWithSections,
|
||||
} from './components';
|
||||
import { selectPropDefs } from './props-definition';
|
||||
import {
|
||||
selectPropDefs,
|
||||
optionPropDefs,
|
||||
optionSectionPropDefs,
|
||||
} from './props-definition';
|
||||
import {
|
||||
selectUsageSnippet,
|
||||
selectDefaultSnippet,
|
||||
@@ -26,6 +32,8 @@ import {
|
||||
selectMultipleSnippet,
|
||||
selectSearchableMultipleSnippet,
|
||||
selectDisabledOptionsSnippet,
|
||||
selectSectionsSnippet,
|
||||
selectSearchableSectionsSnippet,
|
||||
} from './snippets';
|
||||
import { PageTitle } from '@/components/PageTitle';
|
||||
import { Theming } from '@/components/Theming';
|
||||
@@ -58,6 +66,18 @@ export const reactAriaUrls = {
|
||||
|
||||
<ReactAriaLink component="Select" href={reactAriaUrls.select} />
|
||||
|
||||
### Option types
|
||||
|
||||
The `options` prop accepts an array containing either of the following shapes.
|
||||
|
||||
#### `Option`
|
||||
|
||||
<PropsTable data={optionPropDefs} />
|
||||
|
||||
#### `OptionSection`
|
||||
|
||||
<PropsTable data={optionSectionPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
### Label and description
|
||||
@@ -136,6 +156,29 @@ Combine search and multiple selection.
|
||||
code={selectSearchableMultipleSnippet}
|
||||
/>
|
||||
|
||||
### With sections
|
||||
|
||||
Group options under section headings by passing objects with a `title` and a
|
||||
nested `options` array.
|
||||
|
||||
<Snippet
|
||||
layout="side-by-side"
|
||||
open
|
||||
preview={<WithSections />}
|
||||
code={selectSectionsSnippet}
|
||||
/>
|
||||
|
||||
### Searchable with sections
|
||||
|
||||
Sections are preserved when filtering with `searchable`.
|
||||
|
||||
<Snippet
|
||||
layout="side-by-side"
|
||||
open
|
||||
preview={<SearchableWithSections />}
|
||||
code={selectSearchableSectionsSnippet}
|
||||
/>
|
||||
|
||||
### Responsive
|
||||
|
||||
Size can change at different breakpoints.
|
||||
|
||||
@@ -5,30 +5,48 @@ import {
|
||||
} from '@/utils/propDefs';
|
||||
import { Chip } from '@/components/Chip';
|
||||
|
||||
export const optionPropDefs: Record<string, PropDef> = {
|
||||
value: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Unique value for the option.',
|
||||
},
|
||||
label: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Display text for the option.',
|
||||
},
|
||||
disabled: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the option is disabled.',
|
||||
},
|
||||
};
|
||||
|
||||
export const optionSectionPropDefs: Record<string, PropDef> = {
|
||||
title: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Heading displayed above the grouped options.',
|
||||
},
|
||||
options: {
|
||||
type: 'enum',
|
||||
values: ['Option[]'],
|
||||
required: true,
|
||||
description: 'Options nested inside the section.',
|
||||
},
|
||||
};
|
||||
|
||||
export const selectPropDefs: Record<string, PropDef> = {
|
||||
options: {
|
||||
type: 'complex',
|
||||
description: 'Array of options to display in the dropdown.',
|
||||
complexType: {
|
||||
name: 'SelectOption[]',
|
||||
properties: {
|
||||
value: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Unique value for the option.',
|
||||
},
|
||||
label: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Display text for the option.',
|
||||
},
|
||||
disabled: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
description: 'Whether the option is disabled.',
|
||||
},
|
||||
},
|
||||
},
|
||||
type: 'enum',
|
||||
values: ['(Option | OptionSection)[]'],
|
||||
description: (
|
||||
<>
|
||||
Options to display in the dropdown. Pass <Chip>Option</Chip> objects
|
||||
directly, or <Chip>OptionSection</Chip> objects to render grouped
|
||||
options under section headings.
|
||||
</>
|
||||
),
|
||||
},
|
||||
selectionMode: {
|
||||
type: 'enum',
|
||||
|
||||
@@ -110,3 +110,49 @@ export const selectDisabledOptionsSnippet = `<Select
|
||||
{ value: 'cursive', label: 'Cursive' },
|
||||
]}
|
||||
/>`;
|
||||
|
||||
export const selectSectionsSnippet = `<Select
|
||||
name="font"
|
||||
label="Font Family"
|
||||
options={[
|
||||
{
|
||||
title: 'Serif Fonts',
|
||||
options: [
|
||||
{ value: 'times', label: 'Times New Roman' },
|
||||
{ value: 'georgia', label: 'Georgia' },
|
||||
{ value: 'garamond', label: 'Garamond' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Sans-Serif Fonts',
|
||||
options: [
|
||||
{ value: 'arial', label: 'Arial' },
|
||||
{ value: 'helvetica', label: 'Helvetica' },
|
||||
{ value: 'verdana', label: 'Verdana' },
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>`;
|
||||
|
||||
export const selectSearchableSectionsSnippet = `<Select
|
||||
name="font"
|
||||
label="Font Family"
|
||||
searchable
|
||||
searchPlaceholder="Search fonts..."
|
||||
options={[
|
||||
{
|
||||
title: 'Serif Fonts',
|
||||
options: [
|
||||
{ value: 'times', label: 'Times New Roman' },
|
||||
{ value: 'georgia', label: 'Georgia' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Sans-Serif Fonts',
|
||||
options: [
|
||||
{ value: 'arial', label: 'Arial' },
|
||||
{ value: 'helvetica', label: 'Helvetica' },
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>`;
|
||||
|
||||
Reference in New Issue
Block a user