-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
/
Copy pathFormDataConsumer.tsx
133 lines (119 loc) · 3.84 KB
/
FormDataConsumer.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
import * as React from 'react';
import { ReactNode, FunctionComponent } from 'react';
import { useFormState } from 'react-final-form';
import { FormSubscription } from 'final-form';
import get from 'lodash/get';
import warning from '../util/warning';
export interface FormDataConsumerRenderParams {
formData: any;
scopedFormData?: any;
getSource?: (source: string) => string;
}
export type FormDataConsumerRender = (
params: FormDataConsumerRenderParams
) => ReactNode;
interface ConnectedProps {
children: FormDataConsumerRender;
form?: string;
record?: any;
source?: string;
subscription?: FormSubscription;
[key: string]: any;
}
interface Props extends ConnectedProps {
formData: any;
index?: number;
}
/**
* Get the current (edited) value of the record from the form and pass it
* to child function
*
* @example
*
* const PostEdit = (props) => (
* <Edit {...props}>
* <SimpleForm>
* <BooleanInput source="hasEmail" />
* <FormDataConsumer>
* {({ formData, ...rest }) => formData.hasEmail &&
* <TextInput source="email" {...rest} />
* }
* </FormDataConsumer>
* </SimpleForm>
* </Edit>
* );
*
* @example
*
* const OrderEdit = (props) => (
* <Edit {...props}>
* <SimpleForm>
* <SelectInput source="country" choices={countries} />
* <FormDataConsumer>
* {({ formData, ...rest }) =>
* <SelectInput
* source="city"
* choices={getCitiesFor(formData.country)}
* {...rest}
* />
* }
* </FormDataConsumer>
* </SimpleForm>
* </Edit>
* );
*/
const FormDataConsumer = ({ subscription, ...props }: ConnectedProps) => {
const formState = useFormState({ subscription });
return <FormDataConsumerView formData={formState.values} {...props} />;
};
export const FormDataConsumerView: FunctionComponent<Props> = ({
children,
form,
formData,
source,
index,
...rest
}) => {
let scopedFormData = formData;
let getSource;
let getSourceHasBeenCalled = false;
let ret;
// If we have an index, we are in an iterator like component (such as the SimpleFormIterator)
if (typeof index !== 'undefined') {
scopedFormData = get(formData, source);
getSource = (scopedSource: string) => {
getSourceHasBeenCalled = true;
return `${source}.${scopedSource}`;
};
ret = children({ formData, scopedFormData, getSource, ...rest });
} else {
ret = children({ formData, ...rest });
}
warning(
typeof index !== 'undefined' && ret && !getSourceHasBeenCalled,
`You're using a FormDataConsumer inside an ArrayInput and you did not call the getSource function supplied by the FormDataConsumer component. This is required for your inputs to get the proper source.
<ArrayInput source="users">
<SimpleFormIterator>
<TextInput source="name" />
<FormDataConsumer>
{({
formData, // The whole form data
scopedFormData, // The data for this item of the ArrayInput
getSource, // A function to get the valid source inside an ArrayInput
...rest,
}) =>
scopedFormData.name ? (
<SelectInput
source={getSource('role')} // Will translate to "users[0].role"
choices={['admin', 'user']}
{...rest}
/>
) : null
}
</FormDataConsumer>
</SimpleFormIterator>
</ArrayInput>`
);
return ret === undefined ? null : ret;
};
export default FormDataConsumer;