diff options
Diffstat (limited to 'src/components/ui/Select.tsx')
-rw-r--r-- | src/components/ui/Select.tsx | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/src/components/ui/Select.tsx b/src/components/ui/Select.tsx new file mode 100644 index 000000000..1d69a9acf --- /dev/null +++ b/src/components/ui/Select.tsx | |||
@@ -0,0 +1,112 @@ | |||
1 | import { | ||
2 | createRef, | ||
3 | Component, | ||
4 | ReactElement, | ||
5 | RefObject, | ||
6 | ChangeEvent, | ||
7 | } from 'react'; | ||
8 | import { observer } from 'mobx-react'; | ||
9 | import classnames from 'classnames'; | ||
10 | import { Field } from '../../@types/mobx-form.types'; | ||
11 | |||
12 | interface IProps { | ||
13 | field: Field; | ||
14 | className?: string; | ||
15 | showLabel?: boolean; | ||
16 | disabled?: boolean; | ||
17 | multiple?: boolean; | ||
18 | } | ||
19 | |||
20 | // Can this file be merged into the './select/index.tsx' file? | ||
21 | @observer | ||
22 | class Select extends Component<IProps> { | ||
23 | private element: RefObject<HTMLSelectElement> = | ||
24 | createRef<HTMLSelectElement>(); | ||
25 | |||
26 | constructor(props: IProps) { | ||
27 | super(props); | ||
28 | } | ||
29 | |||
30 | multipleChange(e: ChangeEvent<HTMLSelectElement>): void { | ||
31 | e.preventDefault(); | ||
32 | if (!this.element.current) { | ||
33 | return; | ||
34 | } | ||
35 | const result: string[] = []; | ||
36 | const { options } = this.element.current; | ||
37 | for (const option of options) { | ||
38 | if (option.selected && (option.value || option.text)) { | ||
39 | result.push(option.value || option.text); | ||
40 | } | ||
41 | } | ||
42 | |||
43 | const { field } = this.props; | ||
44 | field.value = result; | ||
45 | } | ||
46 | |||
47 | render(): ReactElement { | ||
48 | const { | ||
49 | field, | ||
50 | className = null, | ||
51 | showLabel = true, | ||
52 | disabled = false, | ||
53 | multiple = false, | ||
54 | } = this.props; | ||
55 | |||
56 | let selected = field.value; | ||
57 | |||
58 | if (multiple) { | ||
59 | if (typeof field.value === 'string' && field.value.slice(0, 1) === '[') { | ||
60 | // Value is JSON encoded | ||
61 | selected = JSON.parse(field.value); | ||
62 | } else if (typeof field.value === 'object') { | ||
63 | selected = field.value; | ||
64 | } else { | ||
65 | selected = [field.value]; | ||
66 | } | ||
67 | } | ||
68 | |||
69 | return ( | ||
70 | <div | ||
71 | className={classnames({ | ||
72 | 'franz-form__field': true, | ||
73 | 'has-error': field.error, | ||
74 | 'is-disabled': disabled, | ||
75 | [`${className}`]: className, | ||
76 | })} | ||
77 | > | ||
78 | {field.label && showLabel && ( | ||
79 | <label className="franz-form__label" htmlFor={field.name}> | ||
80 | {field.label} | ||
81 | </label> | ||
82 | )} | ||
83 | <select | ||
84 | onChange={ | ||
85 | multiple | ||
86 | ? (e: ChangeEvent<HTMLSelectElement>) => this.multipleChange(e) | ||
87 | : field.onChange | ||
88 | } | ||
89 | id={field.id} | ||
90 | defaultValue={selected} | ||
91 | className="franz-form__select" | ||
92 | disabled={field.disabled || disabled} | ||
93 | multiple={multiple} | ||
94 | ref={this.element} | ||
95 | > | ||
96 | {field.options!.map(type => ( | ||
97 | <option | ||
98 | key={type.value} | ||
99 | value={type.value} | ||
100 | disabled={type.disabled} | ||
101 | > | ||
102 | {type.label} | ||
103 | </option> | ||
104 | ))} | ||
105 | </select> | ||
106 | {field.error && <div className="franz-form__error">{field.error}</div>} | ||
107 | </div> | ||
108 | ); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | export default Select; | ||