-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathSelect.jsx
More file actions
110 lines (95 loc) · 2.69 KB
/
Select.jsx
File metadata and controls
110 lines (95 loc) · 2.69 KB
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import React, { forwardRef, useRef, startTransition } from "react";
import { getIn, useFormikContext, useField } from "formik";
import { existsBy } from "neetocist";
import PropTypes from "prop-types";
import { prop, either, isNil, isEmpty, dissoc, flatten, pluck } from "ramda";
import Select from "components/Select";
const SelectField = forwardRef((props, ref) => {
const {
name = "",
options = [],
getOptionValue = null,
isMulti = false,
...otherProps
} = props;
const [field, meta, { setValue, setTouched }] = useField(name);
const { status = {}, setStatus } = useFormikContext();
const fieldStatus = getIn(status, name);
const isMenuOpen = useRef(otherProps.defaultMenuIsOpen);
const getRealOptionValue = option => {
if (typeof getOptionValue !== "function") {
return option.value;
}
return getOptionValue(option);
};
const buildValueObj = (value, options) => {
if (typeof value === "object") return value;
const isGrouped = existsBy({ options: Array.isArray }, options);
let searchOptions = options;
if (isGrouped) {
searchOptions = flatten(pluck("options", options));
}
return searchOptions.filter(
option => getRealOptionValue(option) === value
)[0];
};
return (
<Select
{...{ options }}
error={meta.touched ? meta.error || fieldStatus : ""}
getOptionValue={getOptionValue || prop("value")}
innerRef={ref}
isMulti={!!isMulti}
name={field.name}
value={
either(isNil, isEmpty)(field.value)
? null
: buildValueObj(field.value, options)
}
onBlur={() =>
startTransition(() => {
setTouched(true);
})
}
onChange={value => {
setStatus(dissoc(name, status));
setValue(value);
}}
{...otherProps}
onKeyDown={event => {
if (event.key === "Enter" && isMenuOpen.current) {
event.stopPropagation();
}
otherProps.onKeyDown?.(event);
}}
onMenuClose={() => {
isMenuOpen.current = false;
otherProps.onMenuClose?.();
}}
onMenuOpen={() => {
isMenuOpen.current = true;
otherProps.onMenuOpen?.();
}}
/>
);
});
SelectField.displayName = "SelectField";
SelectField.propTypes = {
/**
* The name of the select input.
*/
name: PropTypes.string,
/**
* To provide the options to be displayed in the select component.
*/
options: PropTypes.array,
/**
* To provide the function to get the value of the option.
*/
getOptionValue: PropTypes.string,
/**
* To specify whether multiple options can be selected.
*/
isMulti: PropTypes.bool,
};
export default SelectField;