/
Select.tsx
87 lines (71 loc) · 2.55 KB
/
Select.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import React, { FunctionComponent, ChangeEvent, Validator } from 'react';
import PropTypes from 'prop-types';
import { Form } from '@storybook/components';
import { KnobControlConfig, KnobControlProps } from './types';
export type SelectTypeKnobValue = string | number | null | undefined | PropertyKey[];
export type SelectTypeOptionsProp<T extends SelectTypeKnobValue = SelectTypeKnobValue> =
| Record<PropertyKey, T>
| Record<Extract<T, PropertyKey>, T[keyof T]>
| Extract<T, PropertyKey>[]
| readonly Extract<T, PropertyKey>[];
export interface SelectTypeKnob<T extends SelectTypeKnobValue = SelectTypeKnobValue>
extends KnobControlConfig<T> {
options: SelectTypeOptionsProp<T>;
}
export interface SelectTypeProps<T extends SelectTypeKnobValue = SelectTypeKnobValue>
extends KnobControlProps<T> {
knob: SelectTypeKnob<T>;
}
const serialize = (value: SelectTypeKnobValue) => value;
const deserialize = (value: SelectTypeKnobValue) => value;
const SelectType: FunctionComponent<SelectTypeProps> & {
serialize: typeof serialize;
deserialize: typeof deserialize;
} = ({ knob, onChange }) => {
const { options } = knob;
const callbackReduceArrayOptions = (acc: any, option: any, i: number) => {
if (typeof option !== 'object') return { ...acc, [option]: option };
const label = option.label || option.key || i;
return { ...acc, [label]: option };
};
const entries = Array.isArray(options) ? options.reduce(callbackReduceArrayOptions, {}) : options;
const selectedKey = Object.keys(entries).find(key => {
const { value: knobVal } = knob;
const entryVal = entries[key];
if (Array.isArray(knobVal)) {
return JSON.stringify(entryVal) === JSON.stringify(knobVal);
}
return entryVal === knobVal;
});
return (
<Form.Select
value={selectedKey}
name={knob.name}
onChange={(e: ChangeEvent<HTMLSelectElement>) => {
onChange(entries[e.target.value]);
}}
size="flex"
>
{Object.entries(entries).map(([key]) => (
<option key={key} value={key}>
{key}
</option>
))}
</Form.Select>
);
};
SelectType.defaultProps = {
knob: {} as any,
onChange: value => value,
};
SelectType.propTypes = {
knob: PropTypes.shape({
name: PropTypes.string,
value: PropTypes.any,
options: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
}) as Validator<SelectTypeProps['knob']>,
onChange: PropTypes.func as Validator<SelectTypeProps['onChange']>,
};
SelectType.serialize = serialize;
SelectType.deserialize = deserialize;
export default SelectType;