mirror of
https://github.com/grafana/grafana.git
synced 2025-02-10 23:55:47 -06:00
Select: updates story from knobs to control (#33954)
* Select: updates story from knobs to control * exported default storybook config as meta * disables non-functional controls
This commit is contained in:
parent
b0094b325e
commit
8c03b80490
@ -3,10 +3,12 @@ import { withCenteredStory, withHorizontallyCenteredStory } from '../../utils/st
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { Icon, Select, AsyncSelect, MultiSelect, AsyncMultiSelect } from '@grafana/ui';
|
||||
import { getAvailableIcons, IconName } from '../../types';
|
||||
import { select, boolean, number } from '@storybook/addon-knobs';
|
||||
import { SelectCommonProps } from './types';
|
||||
import { Meta, Story } from '@storybook/react';
|
||||
import { kebabCase } from 'lodash';
|
||||
import { generateOptions } from './mockOptions';
|
||||
import mdx from './Select.mdx';
|
||||
import { auto } from '@popperjs/core';
|
||||
|
||||
export default {
|
||||
title: 'Forms/Select',
|
||||
@ -17,10 +19,56 @@ export default {
|
||||
docs: {
|
||||
page: mdx,
|
||||
},
|
||||
knobs: {
|
||||
disable: true,
|
||||
},
|
||||
controls: {
|
||||
exclude: [
|
||||
'getOptionValue',
|
||||
'getOptionLabel',
|
||||
'formatCreateLabel',
|
||||
'filterOption',
|
||||
'className',
|
||||
'components',
|
||||
'defaultValue',
|
||||
'id',
|
||||
'inputId',
|
||||
'onBlur',
|
||||
'onChange',
|
||||
'onCloseMenu',
|
||||
'onCreateOption',
|
||||
'onInputChange',
|
||||
'onKeyDown',
|
||||
'onOpenMenu',
|
||||
'prefix',
|
||||
'renderControl',
|
||||
'options',
|
||||
'isOptionDisabled',
|
||||
'maxVisibleValues',
|
||||
'aria-label',
|
||||
'noOptionsMessage',
|
||||
'menuPosition',
|
||||
'value',
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const BEHAVIOUR_GROUP = 'Behaviour props';
|
||||
args: {
|
||||
width: 0,
|
||||
disabled: false,
|
||||
isLoading: false,
|
||||
invalid: false,
|
||||
icon: 'arrow-down',
|
||||
},
|
||||
argTypes: {
|
||||
width: { control: { type: 'range', min: 1, max: 100 } },
|
||||
icon: {
|
||||
control: {
|
||||
type: 'select',
|
||||
options: getAvailableIcons(),
|
||||
},
|
||||
},
|
||||
},
|
||||
} as Meta;
|
||||
|
||||
const loadAsyncOptions = () => {
|
||||
return new Promise<Array<SelectableValue<string>>>((resolve) => {
|
||||
@ -30,63 +78,16 @@ const loadAsyncOptions = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const getKnobs = () => {
|
||||
const disabled = boolean('Disabled', false, BEHAVIOUR_GROUP);
|
||||
const invalid = boolean('Invalid', false, BEHAVIOUR_GROUP);
|
||||
const loading = boolean('Loading', false, BEHAVIOUR_GROUP);
|
||||
const prefixSuffixOpts = {
|
||||
None: null,
|
||||
Text: '$',
|
||||
...getAvailableIcons().reduce<Record<string, string>>((prev, c) => {
|
||||
return {
|
||||
...prev,
|
||||
[`Icon: ${c}`]: `icon-${c}`,
|
||||
};
|
||||
}, {}),
|
||||
};
|
||||
const VISUAL_GROUP = 'Visual options';
|
||||
// ---
|
||||
const prefix = select('Prefix', prefixSuffixOpts, null, VISUAL_GROUP);
|
||||
const width = number('Width', 0, undefined, VISUAL_GROUP);
|
||||
|
||||
let prefixEl: any = prefix;
|
||||
if (prefix && prefix.match(/icon-/g)) {
|
||||
prefixEl = <Icon name={prefix.replace(/icon-/g, '') as IconName} />;
|
||||
}
|
||||
|
||||
return {
|
||||
width,
|
||||
disabled,
|
||||
invalid,
|
||||
loading,
|
||||
prefixEl,
|
||||
};
|
||||
const getPrefix = (prefix: string) => {
|
||||
const prefixEl = <Icon name={prefix as IconName} />;
|
||||
return prefixEl;
|
||||
};
|
||||
|
||||
const getMultiSelectKnobs = () => {
|
||||
const isClearable = boolean('Clearable', false, BEHAVIOUR_GROUP);
|
||||
const closeMenuOnSelect = boolean('Close on Select', false, BEHAVIOUR_GROUP);
|
||||
const maxVisibleValues = number('Max. visible values', 5, undefined, BEHAVIOUR_GROUP);
|
||||
interface StoryProps extends Partial<SelectCommonProps<string>> {
|
||||
icon: string;
|
||||
}
|
||||
|
||||
return {
|
||||
isClearable,
|
||||
closeMenuOnSelect,
|
||||
maxVisibleValues,
|
||||
};
|
||||
};
|
||||
|
||||
const getDynamicProps = () => {
|
||||
const knobs = getKnobs();
|
||||
return {
|
||||
width: knobs.width,
|
||||
disabled: knobs.disabled,
|
||||
isLoading: knobs.loading,
|
||||
invalid: knobs.invalid,
|
||||
prefix: knobs.prefixEl,
|
||||
};
|
||||
};
|
||||
|
||||
export const Basic = () => {
|
||||
export const Basic: Story<StoryProps> = (args) => {
|
||||
const [value, setValue] = useState<SelectableValue<string>>();
|
||||
|
||||
return (
|
||||
@ -97,16 +98,16 @@ export const Basic = () => {
|
||||
onChange={(v) => {
|
||||
setValue(v);
|
||||
}}
|
||||
{...getDynamicProps()}
|
||||
prefix={getPrefix(args.icon)}
|
||||
{...args}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Uses plain values instead of SelectableValue<T>
|
||||
*/
|
||||
export const BasicSelectPlainValue = () => {
|
||||
export const BasicSelectPlainValue: Story<StoryProps> = (args) => {
|
||||
const [value, setValue] = useState<string>();
|
||||
return (
|
||||
<>
|
||||
@ -116,16 +117,16 @@ export const BasicSelectPlainValue = () => {
|
||||
onChange={(v) => {
|
||||
setValue(v.value);
|
||||
}}
|
||||
{...getDynamicProps()}
|
||||
prefix={getPrefix(args.icon)}
|
||||
{...args}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Uses plain values instead of SelectableValue<T>
|
||||
*/
|
||||
export const SelectWithOptionDescriptions = () => {
|
||||
export const SelectWithOptionDescriptions: Story = (args) => {
|
||||
// TODO this is not working with new Select
|
||||
|
||||
const [value, setValue] = useState<number>();
|
||||
@ -148,7 +149,8 @@ export const SelectWithOptionDescriptions = () => {
|
||||
onChange={(v) => {
|
||||
setValue(v.value);
|
||||
}}
|
||||
{...getDynamicProps()}
|
||||
prefix={getPrefix(args.icon)}
|
||||
{...args}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
@ -157,7 +159,7 @@ export const SelectWithOptionDescriptions = () => {
|
||||
/**
|
||||
* Uses plain values instead of SelectableValue<T>
|
||||
*/
|
||||
export const MultiPlainValue = () => {
|
||||
export const MultiPlainValue: Story = (args) => {
|
||||
const [value, setValue] = useState<string[]>();
|
||||
|
||||
return (
|
||||
@ -168,13 +170,14 @@ export const MultiPlainValue = () => {
|
||||
onChange={(v) => {
|
||||
setValue(v.map((v: any) => v.value));
|
||||
}}
|
||||
{...getDynamicProps()}
|
||||
prefix={getPrefix(args.icon)}
|
||||
{...args}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const MultiSelectWithOptionGroups = () => {
|
||||
export const MultiSelectWithOptionGroups: Story = (args) => {
|
||||
const [value, setValue] = useState<string[]>();
|
||||
|
||||
return (
|
||||
@ -188,13 +191,14 @@ export const MultiSelectWithOptionGroups = () => {
|
||||
onChange={(v) => {
|
||||
setValue(v.map((v: any) => v.value));
|
||||
}}
|
||||
{...getDynamicProps()}
|
||||
prefix={getPrefix(args.icon)}
|
||||
{...args}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const MultiSelectBasic = () => {
|
||||
export const MultiSelectBasic: Story = (args) => {
|
||||
const [value, setValue] = useState<Array<SelectableValue<string>>>([]);
|
||||
|
||||
return (
|
||||
@ -205,14 +209,19 @@ export const MultiSelectBasic = () => {
|
||||
onChange={(v) => {
|
||||
setValue(v);
|
||||
}}
|
||||
{...getDynamicProps()}
|
||||
{...getMultiSelectKnobs()}
|
||||
prefix={getPrefix(args.icon)}
|
||||
{...args}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
MultiSelectBasic.args = {
|
||||
isClearable: false,
|
||||
closeMenuOnSelect: false,
|
||||
maxVisibleValues: 5,
|
||||
};
|
||||
|
||||
export const MultiSelectAsync = () => {
|
||||
export const MultiSelectAsync: Story = (args) => {
|
||||
const [value, setValue] = useState<Array<SelectableValue<string>>>();
|
||||
|
||||
return (
|
||||
@ -223,13 +232,16 @@ export const MultiSelectAsync = () => {
|
||||
onChange={(v) => {
|
||||
setValue(v);
|
||||
}}
|
||||
allowCustomValue
|
||||
{...getDynamicProps()}
|
||||
prefix={getPrefix(args.icon)}
|
||||
{...args}
|
||||
/>
|
||||
);
|
||||
};
|
||||
MultiSelectAsync.args = {
|
||||
allowCustomValue: false,
|
||||
};
|
||||
|
||||
export const BasicSelectAsync = () => {
|
||||
export const BasicSelectAsync: Story = (args) => {
|
||||
const [value, setValue] = useState<SelectableValue<string>>();
|
||||
|
||||
return (
|
||||
@ -240,12 +252,13 @@ export const BasicSelectAsync = () => {
|
||||
onChange={(v) => {
|
||||
setValue(v);
|
||||
}}
|
||||
{...getDynamicProps()}
|
||||
prefix={getPrefix(args.icon)}
|
||||
{...args}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const AutoMenuPlacement = () => {
|
||||
export const AutoMenuPlacement: Story = (args) => {
|
||||
const [value, setValue] = useState<SelectableValue<string>>();
|
||||
|
||||
return (
|
||||
@ -257,14 +270,18 @@ export const AutoMenuPlacement = () => {
|
||||
onChange={(v) => {
|
||||
setValue(v);
|
||||
}}
|
||||
{...getDynamicProps()}
|
||||
prefix={getPrefix(args.icon)}
|
||||
{...args}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
AutoMenuPlacement.args = {
|
||||
menuPlacement: auto,
|
||||
};
|
||||
|
||||
export const CustomValueCreation = () => {
|
||||
export const CustomValueCreation: Story = (args) => {
|
||||
const [value, setValue] = useState<SelectableValue<string>>();
|
||||
const [customOptions, setCustomOptions] = useState<Array<SelectableValue<string>>>([]);
|
||||
const options = generateOptions();
|
||||
@ -276,14 +293,18 @@ export const CustomValueCreation = () => {
|
||||
onChange={(v) => {
|
||||
setValue(v);
|
||||
}}
|
||||
allowCustomValue
|
||||
allowCustomValue={args.allowCustomValue}
|
||||
onCreateOption={(v) => {
|
||||
const customValue: SelectableValue<string> = { value: kebabCase(v), label: v };
|
||||
setCustomOptions([...customOptions, customValue]);
|
||||
setValue(customValue);
|
||||
}}
|
||||
{...getDynamicProps()}
|
||||
prefix={getPrefix(args.icon)}
|
||||
{...args}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
CustomValueCreation.args = {
|
||||
allowCustomValue: true,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user