-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
/
Copy pathSelectField.tsx
150 lines (138 loc) · 4.52 KB
/
SelectField.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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import * as React from 'react';
import { FC, memo } from 'react';
import PropTypes from 'prop-types';
import get from 'lodash/get';
import { ChoicesProps, useChoices } from 'ra-core';
import Typography from '@material-ui/core/Typography';
import sanitizeFieldRestProps from './sanitizeFieldRestProps';
import { PublicFieldProps, InjectedFieldProps, fieldPropTypes } from './types';
/**
* Display a value in an enumeration
*
* Pass possible options as an array of objects in the 'choices' attribute.
*
* @example
* const choices = [
* { id: 'M', name: 'Male' },
* { id: 'F', name: 'Female' },
* ];
* <SelectField source="gender" choices={choices} />
*
* By default, the text is built by
* - finding a choice where the 'id' property equals the field value
* - using the 'name' property an the option text
*
* You can also customize the properties to use for the value and text,
* thanks to the 'optionValue' and 'optionText' attributes.
*
* @example
* const choices = [
* { _id: 123, full_name: 'Leo Tolstoi', sex: 'M' },
* { _id: 456, full_name: 'Jane Austen', sex: 'F' },
* ];
* <SelectField source="author_id" choices={choices} optionText="full_name" optionValue="_id" />
*
* `optionText` also accepts a function, so you can shape the option text at will:
* @example
* const choices = [
* { id: 123, first_name: 'Leo', last_name: 'Tolstoi' },
* { id: 456, first_name: 'Jane', last_name: 'Austen' },
* ];
* const optionRenderer = choice => `${choice.first_name} ${choice.last_name}`;
* <SelectField source="author_id" choices={choices} optionText={optionRenderer} />
*
* `optionText` also accepts a React Element, that will be cloned and receive
* the related choice as the `record` prop. You can use Field components there.
* @example
* const choices = [
* { id: 123, first_name: 'Leo', last_name: 'Tolstoi' },
* { id: 456, first_name: 'Jane', last_name: 'Austen' },
* ];
* const FullNameField = ({ record }) => <Chip>{record.first_name} {record.last_name}</Chip>;
* <SelectField source="gender" choices={choices} optionText={<FullNameField />}/>
*
* The current choice is translated by default, so you can use translation identifiers as choices:
* @example
* const choices = [
* { id: 'M', name: 'myroot.gender.male' },
* { id: 'F', name: 'myroot.gender.female' },
* ];
*
* However, in some cases (e.g. inside a `<ReferenceField>`), you may not want
* the choice to be translated. In that case, set the `translateChoice` prop to false.
* @example
* <SelectField source="gender" choices={choices} translateChoice={false}/>
*
* **Tip**: <ReferenceField> sets `translateChoice` to false by default.
*/
export const SelectField: FC<SelectFieldProps> = memo<SelectFieldProps>(
({
className,
emptyText,
source,
record,
choices,
optionValue,
optionText,
translateChoice,
...rest
}) => {
const value = get(record, source);
const { getChoiceText, getChoiceValue } = useChoices({
optionText,
optionValue,
translateChoice,
});
const choice = choices.find(choice => getChoiceValue(choice) === value);
if (!choice) {
return emptyText ? (
<Typography
component="span"
variant="body2"
className={className}
{...sanitizeFieldRestProps(rest)}
>
{emptyText}
</Typography>
) : null;
}
let choiceText = getChoiceText(choice);
return (
<Typography
component="span"
variant="body2"
className={className}
{...sanitizeFieldRestProps(rest)}
>
{choiceText}
</Typography>
);
}
);
SelectField.defaultProps = {
optionText: 'name',
optionValue: 'id',
translateChoice: true,
};
SelectField.defaultProps = {
addLabel: true,
};
SelectField.propTypes = {
// @ts-ignore
...Typography.propTypes,
...fieldPropTypes,
choices: PropTypes.arrayOf(PropTypes.object).isRequired,
optionText: PropTypes.oneOfType([
PropTypes.string,
PropTypes.func,
PropTypes.element,
]),
optionValue: PropTypes.string,
translateChoice: PropTypes.bool,
};
export interface SelectFieldProps
extends ChoicesProps,
PublicFieldProps,
InjectedFieldProps {}
SelectField.displayName = 'SelectField';
export default SelectField;