Commit fa6a43c6 by Tobias Skarhed Committed by GitHub

Docs: Select (#23398)

* Start Select docs

* Writ emore docs

* Apply suggestions from code review

Co-Authored-By: Alex Khomenko <Clarity-89@users.noreply.github.com>

Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>
parent b980cedf
import { Props, Preview } from "@storybook/addon-docs/blocks";
import { Select, AsyncSelect, MultiSelect, AsyncMultiSelect } from "./Select";
import { generateOptions } from "./mockOptions";
# Select variants
Select is an input with the ability to search and create new values. It should be used when you have a list of options. If the data has a tree structure, consider using `Cascader` instead.
Select has some features:
- Search a list of values
- Select multiple values
- Select from async data
- Create custom values that aren't in the list
## Select
Select is the base for every component on this page. The approaches mentioned here are also applicable to `AsyncSelect`, `MultiSelect`, `AsyncMultiSelect`.
### Options format
There are four properties for each option:
- `label` - Text that is visible in the menu.
- `value` - Could be anything, but is usually a string. Used to identify what is **actually** selected.
- `description` - Longer description that describes the choice. Use this sparingly.
- `imgUrl` - URL to an image. Use this when an image or icon provides more context for the option.
```jsx
const options = [
{ label: "Basic option", value: 0 },
{ label: "Option with description", value: 1, description: "this is a description" },
{
label: "Option with description and image",
value: 2,
description: "This is a very elaborate description, describing all the wonders in the world.",
imgUrl: "https://placekitten.com/40/40",
},
];
```
### Creatable option
Creatable option is used when you want to be able to add a custom value to the list of options. `allowCustomValue` needs to be true and you must handle the value creation with `onCreateOption`.
```jsx
import { Select } from "@grafana/ui";
const SelectComponent = () => {
const [value, setValue] = useState<SelectableValue<number>>();
return (
<Select
options={option}
value={value}
allowCustomValue
onCreateOption={customValue => {
setValue(customValue);
}}
/>
);
};
```
## AsyncSelect
Like regular Select, but handles fetching options asynchronously. Use the `loadOptions` prop for the async function that loads the options. If `defaultOptions` is set to `true`, `loadOptions` will be called when the component is mounted.
```jsx
import { AsyncSelect } from '@grafana/ui';
const basicSelectAsync = () => {
const [value, setValue] = useState<SelectableValue<string>>();
return (
<AsyncSelect
loadOptions={loadAsyncOptions}
defaultOptions
value={value}
onChange={v => {
setValue(v);
}}
size="md"
/>
);
};
```
Where the async function could look like this:
```tsx
const loadAsyncOptions = () => {
return new Promise()<Array<SelectableValue<string>>>(resolve => {
setTimeout(() => {
resolve(options);
}, 2000);
});
};
```
## MultiSelect
Possible to Select multiple values at the same time.
```tsx
import { MultiSelect } from "@grafana/ui";
const multiSelect = () => {
const [value, setValue] = useState<Array<SelectableValue<string>>>([]);
return (
<>
<MultiSelect
options={options}
value={value}
onChange={v => {
setValue(v);
}}
size="md"
/>
</>
);
};
```
## AsyncMultiSelect
Like MultiSelect but handles data asynchronously with the `loadOptions` prop.
## Props
<Props of={Select} />
...@@ -10,11 +10,18 @@ import { ButtonSelect } from './ButtonSelect'; ...@@ -10,11 +10,18 @@ import { ButtonSelect } from './ButtonSelect';
import { getIconKnob } from '../../utils/storybook/knobs'; import { getIconKnob } from '../../utils/storybook/knobs';
import kebabCase from 'lodash/kebabCase'; import kebabCase from 'lodash/kebabCase';
import { generateOptions } from './mockOptions'; import { generateOptions } from './mockOptions';
import mdx from './Select.mdx';
export default { export default {
title: 'Forms/Select', title: 'Forms/Select',
component: Select, component: Select,
decorators: [withCenteredStory, withHorizontallyCenteredStory], decorators: [withCenteredStory, withHorizontallyCenteredStory],
subcomponents: { AsyncSelect, MultiSelect, AsyncMultiSelect },
parameters: {
docs: {
page: mdx,
},
},
}; };
const loadAsyncOptions = () => { const loadAsyncOptions = () => {
......
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import { kebabCase } from 'lodash'; import { kebabCase } from 'lodash';
export const generateOptions = () => { export const generateOptions = (desc = false) => {
const values = [ const values = [
'Sharilyn Markowitz', 'Sharilyn Markowitz',
'Naomi Striplin', 'Naomi Striplin',
...@@ -28,5 +28,6 @@ export const generateOptions = () => { ...@@ -28,5 +28,6 @@ export const generateOptions = () => {
return values.map<SelectableValue<string>>(name => ({ return values.map<SelectableValue<string>>(name => ({
value: kebabCase(name), value: kebabCase(name),
label: name, label: name,
description: desc ? `This is a description of ${name}` : undefined,
})); }));
}; };
...@@ -6,12 +6,15 @@ export type SelectValue<T> = T | SelectableValue<T> | T[] | Array<SelectableValu ...@@ -6,12 +6,15 @@ export type SelectValue<T> = T | SelectableValue<T> | T[] | Array<SelectableValu
export interface SelectCommonProps<T> { export interface SelectCommonProps<T> {
allowCustomValue?: boolean; allowCustomValue?: boolean;
/** Focus is set to the Select when rendered*/
autoFocus?: boolean; autoFocus?: boolean;
backspaceRemovesValue?: boolean; backspaceRemovesValue?: boolean;
className?: string; className?: string;
/** Used for custom components. For more information, see `react-select` */
components?: any; components?: any;
defaultValue?: any; defaultValue?: any;
disabled?: boolean; disabled?: boolean;
/** Function for formatting the text that is displayed when creating a new value*/
formatCreateLabel?: (input: string) => string; formatCreateLabel?: (input: string) => string;
getOptionLabel?: (item: SelectableValue<T>) => string; getOptionLabel?: (item: SelectableValue<T>) => string;
getOptionValue?: (item: SelectableValue<T>) => string; getOptionValue?: (item: SelectableValue<T>) => string;
...@@ -20,14 +23,17 @@ export interface SelectCommonProps<T> { ...@@ -20,14 +23,17 @@ export interface SelectCommonProps<T> {
isLoading?: boolean; isLoading?: boolean;
isMulti?: boolean; isMulti?: boolean;
isOpen?: boolean; isOpen?: boolean;
/** Disables the possibility to type into the input*/
isSearchable?: boolean; isSearchable?: boolean;
maxMenuHeight?: number; maxMenuHeight?: number;
menuPlacement?: 'auto' | 'bottom' | 'top'; menuPlacement?: 'auto' | 'bottom' | 'top';
menuPosition?: 'fixed' | 'absolute'; menuPosition?: 'fixed' | 'absolute';
/** The message to display when no options could be found */
noOptionsMessage?: string; noOptionsMessage?: string;
onBlur?: () => void; onBlur?: () => void;
onChange: (value: SelectableValue<T>) => {} | void; onChange: (value: SelectableValue<T>) => {} | void;
onCloseMenu?: () => void; onCloseMenu?: () => void;
/** allowCustomValue must be enabled. Function decides what to do with that custom value. */
onCreateOption?: (value: string) => void; onCreateOption?: (value: string) => void;
onInputChange?: (label: string) => void; onInputChange?: (label: string) => void;
onKeyDown?: (event: React.KeyboardEvent) => void; onKeyDown?: (event: React.KeyboardEvent) => void;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment