@proteinjs/ui 2.0.2 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +20 -0
- package/.prettierignore +4 -0
- package/.prettierrc +8 -0
- package/CHANGELOG.md +16 -14
- package/LICENSE +21 -0
- package/dist/generated/index.js +1 -1
- package/dist/generated/index.js.map +1 -1
- package/dist/src/container/AccountIconButton.d.ts +1 -1
- package/dist/src/container/AccountIconButton.d.ts.map +1 -1
- package/dist/src/container/AccountIconButton.js +13 -6
- package/dist/src/container/AccountIconButton.js.map +1 -1
- package/dist/src/container/NavMenu.d.ts.map +1 -1
- package/dist/src/container/NavMenu.js +9 -9
- package/dist/src/container/NavMenu.js.map +1 -1
- package/dist/src/container/PageContainer.d.ts +1 -1
- package/dist/src/container/PageContainer.d.ts.map +1 -1
- package/dist/src/container/PageContainer.js +12 -7
- package/dist/src/container/PageContainer.js.map +1 -1
- package/dist/src/form/Field.d.ts.map +1 -1
- package/dist/src/form/Field.js +4 -2
- package/dist/src/form/Field.js.map +1 -1
- package/dist/src/form/Form.d.ts.map +1 -1
- package/dist/src/form/Form.js +75 -40
- package/dist/src/form/Form.js.map +1 -1
- package/dist/src/form/FormButton.d.ts.map +1 -1
- package/dist/src/form/FormButton.js +1 -1
- package/dist/src/form/FormButton.js.map +1 -1
- package/dist/src/form/container/FormPage.d.ts.map +1 -1
- package/dist/src/form/container/FormPage.js.map +1 -1
- package/dist/src/form/container/FormPaper.js +1 -1
- package/dist/src/form/container/FormPaper.js.map +1 -1
- package/dist/src/form/fields/TextField.d.ts.map +1 -1
- package/dist/src/form/fields/TextField.js +8 -6
- package/dist/src/form/fields/TextField.js.map +1 -1
- package/dist/src/list/NestedList.d.ts.map +1 -1
- package/dist/src/list/NestedList.js +10 -10
- package/dist/src/list/NestedList.js.map +1 -1
- package/dist/src/router/Page.d.ts.map +1 -1
- package/dist/src/router/Router.d.ts.map +1 -1
- package/dist/src/router/Router.js +11 -7
- package/dist/src/router/Router.js.map +1 -1
- package/dist/src/router/createUrlParams.d.ts.map +1 -1
- package/dist/src/router/createUrlParams.js +2 -1
- package/dist/src/router/createUrlParams.js.map +1 -1
- package/dist/src/router/withRouter.d.ts.map +1 -1
- package/dist/src/router/withRouter.js +1 -1
- package/dist/src/router/withRouter.js.map +1 -1
- package/dist/src/table/Table.d.ts +1 -1
- package/dist/src/table/Table.d.ts.map +1 -1
- package/dist/src/table/Table.js +31 -23
- package/dist/src/table/Table.js.map +1 -1
- package/dist/src/table/TableButton.d.ts.map +1 -1
- package/dist/src/table/TableLoader.d.ts.map +1 -1
- package/dist/src/table/TableToolbar.d.ts.map +1 -1
- package/dist/src/table/TableToolbar.js +10 -7
- package/dist/src/table/TableToolbar.js.map +1 -1
- package/generated/index.ts +1 -1
- package/index.ts +1 -1
- package/jest.config.js +8 -17
- package/package.json +56 -50
- package/src/container/AccountIconButton.tsx +103 -102
- package/src/container/NavMenu.tsx +20 -21
- package/src/container/PageContainer.tsx +110 -80
- package/src/form/Field.tsx +42 -35
- package/src/form/Form.tsx +370 -351
- package/src/form/FormButton.tsx +24 -22
- package/src/form/FunctionalForm.tsx +15 -15
- package/src/form/container/FormPage.tsx +16 -18
- package/src/form/container/FormPaper.tsx +12 -12
- package/src/form/fields/TextField.tsx +63 -61
- package/src/list/NestedList.tsx +18 -21
- package/src/router/Page.ts +18 -18
- package/src/router/Router.tsx +66 -52
- package/src/router/createUrlParams.ts +8 -7
- package/src/router/withRouter.tsx +6 -11
- package/src/table/Table.tsx +96 -80
- package/src/table/TableButton.ts +9 -9
- package/src/table/TableLoader.ts +6 -6
- package/src/table/TableToolbar.tsx +52 -59
- package/tsconfig.json +17 -17
package/src/form/Form.tsx
CHANGED
|
@@ -6,400 +6,419 @@ import { FormButton, FormButtons } from './FormButton';
|
|
|
6
6
|
import { withRouter, WithRouterProps } from '../router/withRouter';
|
|
7
7
|
|
|
8
8
|
export type FormProps<F extends Fields, B extends FormButtons<F>> = {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
} & Partial<WithRouterProps
|
|
9
|
+
name?: string;
|
|
10
|
+
documentation?: React.ComponentType;
|
|
11
|
+
createFields: () => F;
|
|
12
|
+
fieldLayout?: (keyof F)[] | (keyof F)[][];
|
|
13
|
+
buttons: B;
|
|
14
|
+
onLoad?: (fields: F, buttons: B) => Promise<void>;
|
|
15
|
+
onLoadProgressMessage?: string;
|
|
16
|
+
} & Partial<WithRouterProps>;
|
|
17
17
|
|
|
18
18
|
export type FormState<F extends Fields> = {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export class FormComponent<F extends Fields, B extends FormButtons<F>> extends React.Component<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
19
|
+
status?: { message?: string; isError?: boolean };
|
|
20
|
+
fields: F;
|
|
21
|
+
progress?: { visible?: boolean; message?: string };
|
|
22
|
+
onLoadExecuted?: boolean;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export class FormComponent<F extends Fields, B extends FormButtons<F>> extends React.Component<
|
|
26
|
+
FormProps<F, B>,
|
|
27
|
+
FormState<F>
|
|
28
|
+
> {
|
|
29
|
+
constructor(props: FormProps<F, B>) {
|
|
30
|
+
super(props);
|
|
31
|
+
this.state = { fields: props.createFields() };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
componentDidMount() {
|
|
35
|
+
if (this.state.onLoadExecuted) {
|
|
36
|
+
return;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
39
|
+
this.onLoad();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private async onLoad() {
|
|
43
|
+
this.setState({ progress: { visible: true, message: this.props.onLoadProgressMessage } });
|
|
44
|
+
const newFields = this.props.createFields();
|
|
45
|
+
try {
|
|
46
|
+
for (const fieldPropertyName in newFields) {
|
|
47
|
+
const field = newFields[fieldPropertyName].field;
|
|
48
|
+
if (!field) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
49
51
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
if (field.onLoad) {
|
|
53
|
+
await field.onLoad(newFields);
|
|
54
|
+
}
|
|
53
55
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
} catch (error) {
|
|
57
|
-
console.error(`Failed while running onLoad functions`, error);
|
|
56
|
+
if (!field.accessibility) {
|
|
57
|
+
field.accessibility = {};
|
|
58
58
|
}
|
|
59
|
+
}
|
|
59
60
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
});
|
|
61
|
+
if (this.props.onLoad) {
|
|
62
|
+
await this.props.onLoad(newFields, this.props.buttons);
|
|
63
|
+
}
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error(`Failed while running onLoad functions`, error);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
68
|
+
this.setState({
|
|
69
|
+
status: {},
|
|
70
|
+
fields: newFields,
|
|
71
|
+
progress: { visible: false },
|
|
72
|
+
onLoadExecuted: true,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private async onChange(
|
|
77
|
+
field: Field<any, any>,
|
|
78
|
+
value: any,
|
|
79
|
+
setFieldStatus: (message: string, isError: boolean) => void
|
|
80
|
+
) {
|
|
81
|
+
field.value = value;
|
|
82
|
+
if (field.onChange) {
|
|
83
|
+
try {
|
|
84
|
+
await field.onChange(field.value, this.state.fields, setFieldStatus);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error(`Failed while running onChange for field: ${field.name}`, error);
|
|
87
|
+
}
|
|
79
88
|
}
|
|
80
89
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
this.setState(this.state);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private async onClick(button: FormButton<any>) {
|
|
94
|
+
if (button.onClick) {
|
|
95
|
+
this.setState({
|
|
96
|
+
progress: {
|
|
97
|
+
visible: true,
|
|
98
|
+
message: button.progressMessage ? button.progressMessage(this.state.fields) : undefined,
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
try {
|
|
102
|
+
const successMessage = await button.onClick(this.state.fields, this.props.buttons);
|
|
103
|
+
if (successMessage) {
|
|
104
|
+
this.setState({ status: { message: successMessage, isError: false } });
|
|
93
105
|
}
|
|
106
|
+
} catch (error: any) {
|
|
107
|
+
this.setState({ status: { message: error.message, isError: true } });
|
|
108
|
+
console.error(`Error when clicking button: ${button.name}`, error);
|
|
109
|
+
}
|
|
110
|
+
this.setState({ progress: { visible: false } });
|
|
111
|
+
}
|
|
94
112
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if (this.props.navigate)
|
|
102
|
-
this.props.navigate(path);
|
|
113
|
+
if (button.redirect) {
|
|
114
|
+
const redirect = await button.redirect(this.state.fields, this.props.buttons);
|
|
115
|
+
let path = redirect.path;
|
|
116
|
+
if (redirect.props) {
|
|
117
|
+
path += `?${queryString.stringify(redirect.props)}`;
|
|
118
|
+
}
|
|
103
119
|
|
|
104
|
-
|
|
105
|
-
|
|
120
|
+
if (this.props.navigate) {
|
|
121
|
+
this.props.navigate(path);
|
|
122
|
+
}
|
|
106
123
|
|
|
107
|
-
|
|
108
|
-
await this.onLoad();
|
|
124
|
+
return;
|
|
109
125
|
}
|
|
110
126
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
<Container sx={{ padding: 0 }} maxWidth={this.getContainerMaxWidth()}>
|
|
114
|
-
<form autoComplete='off'>
|
|
115
|
-
<Grid container>
|
|
116
|
-
{this.Title()}
|
|
117
|
-
{this.Documentation()}
|
|
118
|
-
{this.Status()}
|
|
119
|
-
{this.Fields()}
|
|
120
|
-
{this.Progress()}
|
|
121
|
-
{this.Buttons()}
|
|
122
|
-
</Grid>
|
|
123
|
-
</form>
|
|
124
|
-
</Container>
|
|
125
|
-
);
|
|
127
|
+
if (button.clearFormOnClick) {
|
|
128
|
+
await this.onLoad();
|
|
126
129
|
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
render() {
|
|
133
|
+
return (
|
|
134
|
+
<Container sx={{ padding: 0 }} maxWidth={this.getContainerMaxWidth()}>
|
|
135
|
+
<form autoComplete='off'>
|
|
136
|
+
<Grid container>
|
|
137
|
+
{this.Title()}
|
|
138
|
+
{this.Documentation()}
|
|
139
|
+
{this.Status()}
|
|
140
|
+
{this.Fields()}
|
|
141
|
+
{this.Progress()}
|
|
142
|
+
{this.Buttons()}
|
|
143
|
+
</Grid>
|
|
144
|
+
</form>
|
|
145
|
+
</Container>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private getContainerMaxWidth(): 'xs' | 'sm' {
|
|
150
|
+
if (this.props.fieldLayout) {
|
|
151
|
+
// TODO validate that fields are not hidden
|
|
152
|
+
if (this.props.fieldLayout.length < 2) {
|
|
153
|
+
return 'xs';
|
|
154
|
+
}
|
|
127
155
|
|
|
128
|
-
|
|
129
|
-
if (
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const field = this.state.fields[fieldPropertyName].field;
|
|
141
|
-
if (field.accessibility?.hidden)
|
|
142
|
-
continue;
|
|
143
|
-
|
|
144
|
-
if (!field.layout)
|
|
145
|
-
continue;
|
|
156
|
+
for (const row of this.props.fieldLayout) {
|
|
157
|
+
if ((row as string[]).length > 1) {
|
|
158
|
+
return 'sm';
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
const rows: boolean[] = [];
|
|
163
|
+
for (const fieldPropertyName in this.state.fields) {
|
|
164
|
+
const field = this.state.fields[fieldPropertyName].field;
|
|
165
|
+
if (field.accessibility?.hidden) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
146
168
|
|
|
147
|
-
|
|
148
|
-
|
|
169
|
+
if (!field.layout) {
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
149
172
|
|
|
150
|
-
|
|
151
|
-
|
|
173
|
+
if (rows[field.layout.row]) {
|
|
174
|
+
return 'sm';
|
|
152
175
|
}
|
|
153
176
|
|
|
154
|
-
|
|
177
|
+
rows[field.layout.row] = true;
|
|
178
|
+
}
|
|
155
179
|
}
|
|
156
180
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
return null;
|
|
181
|
+
return 'xs';
|
|
182
|
+
}
|
|
160
183
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
xs={12}
|
|
165
|
-
justifyContent='flex-start'
|
|
166
|
-
alignItems='flex-start'
|
|
167
|
-
sx={(theme) => ({
|
|
168
|
-
marginTop: theme.spacing(1),
|
|
169
|
-
marginBottom: theme.spacing(3),
|
|
170
|
-
})}
|
|
171
|
-
>
|
|
172
|
-
<Typography
|
|
173
|
-
variant='h5'
|
|
174
|
-
>
|
|
175
|
-
{this.props.name}
|
|
176
|
-
</Typography>
|
|
177
|
-
</Grid>
|
|
178
|
-
);
|
|
184
|
+
private Title() {
|
|
185
|
+
if (!this.props.name) {
|
|
186
|
+
return null;
|
|
179
187
|
}
|
|
180
188
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
189
|
+
return (
|
|
190
|
+
<Grid
|
|
191
|
+
container
|
|
192
|
+
xs={12}
|
|
193
|
+
justifyContent='flex-start'
|
|
194
|
+
alignItems='flex-start'
|
|
195
|
+
sx={(theme) => ({
|
|
196
|
+
marginTop: theme.spacing(1),
|
|
197
|
+
marginBottom: theme.spacing(3),
|
|
198
|
+
})}
|
|
199
|
+
>
|
|
200
|
+
<Typography variant='h5'>{this.props.name}</Typography>
|
|
201
|
+
</Grid>
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
private Documentation() {
|
|
206
|
+
if (!this.props.documentation) {
|
|
207
|
+
return null;
|
|
197
208
|
}
|
|
198
|
-
|
|
199
|
-
private Status() {
|
|
200
|
-
if (!this.state.status || !this.state.status.message)
|
|
201
|
-
return null;
|
|
202
209
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
color={this.state.status.isError ? 'error' : 'primary'}
|
|
216
|
-
>
|
|
217
|
-
{this.state.status.message}
|
|
218
|
-
</Typography>
|
|
219
|
-
</Container>
|
|
220
|
-
</Grid>
|
|
221
|
-
);
|
|
210
|
+
return (
|
|
211
|
+
<Grid container xs={12} justifyContent='flex-start' alignItems='flex-start'>
|
|
212
|
+
<Container>
|
|
213
|
+
<this.props.documentation />
|
|
214
|
+
</Container>
|
|
215
|
+
</Grid>
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
private Status() {
|
|
220
|
+
if (!this.state.status || !this.state.status.message) {
|
|
221
|
+
return null;
|
|
222
222
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
223
|
+
|
|
224
|
+
return (
|
|
225
|
+
<Grid container xs={12}>
|
|
226
|
+
<Container
|
|
227
|
+
sx={(theme) => ({
|
|
228
|
+
marginBottom: theme.spacing(1),
|
|
229
|
+
})}
|
|
230
|
+
>
|
|
231
|
+
<Typography variant='subtitle1' color={this.state.status.isError ? 'error' : 'primary'}>
|
|
232
|
+
{this.state.status.message}
|
|
233
|
+
</Typography>
|
|
234
|
+
</Container>
|
|
235
|
+
</Grid>
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
private Fields() {
|
|
240
|
+
return (
|
|
241
|
+
<Grid container direction='column' xs={12}>
|
|
242
|
+
{this.getFieldRows().map((fieldComponents, index) => {
|
|
243
|
+
if (!this.isFieldRowVisible(fieldComponents)) {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return (
|
|
248
|
+
<Grid
|
|
249
|
+
container
|
|
250
|
+
spacing={3}
|
|
251
|
+
alignItems='center'
|
|
252
|
+
sx={(theme) => ({
|
|
253
|
+
flexGrow: 1,
|
|
254
|
+
marginBottom: theme.spacing(3),
|
|
255
|
+
})}
|
|
256
|
+
key={index}
|
|
230
257
|
>
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
})}
|
|
245
|
-
key={index}
|
|
246
|
-
>
|
|
247
|
-
{
|
|
248
|
-
fieldComponents.filter((fieldComponent) => {
|
|
249
|
-
if (fieldComponent.field.accessibility?.hidden)
|
|
250
|
-
return false;
|
|
251
|
-
|
|
252
|
-
return true;
|
|
253
|
-
}).map((fieldComponent) => (
|
|
254
|
-
<Grid item xs key={fieldComponent.field.name}>
|
|
255
|
-
<fieldComponent.component
|
|
256
|
-
field={fieldComponent.field}
|
|
257
|
-
onChange={this.onChange.bind(this)}
|
|
258
|
-
/>
|
|
259
|
-
</Grid>
|
|
260
|
-
))
|
|
261
|
-
}
|
|
262
|
-
</Grid>
|
|
263
|
-
);
|
|
264
|
-
})
|
|
265
|
-
}
|
|
258
|
+
{fieldComponents
|
|
259
|
+
.filter((fieldComponent) => {
|
|
260
|
+
if (fieldComponent.field.accessibility?.hidden) {
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return true;
|
|
265
|
+
})
|
|
266
|
+
.map((fieldComponent) => (
|
|
267
|
+
<Grid item xs key={fieldComponent.field.name}>
|
|
268
|
+
<fieldComponent.component field={fieldComponent.field} onChange={this.onChange.bind(this)} />
|
|
269
|
+
</Grid>
|
|
270
|
+
))}
|
|
266
271
|
</Grid>
|
|
267
|
-
|
|
272
|
+
);
|
|
273
|
+
})}
|
|
274
|
+
</Grid>
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
private getFieldRows(): FieldComponent<any, any>[][] {
|
|
279
|
+
const rows: FieldComponent<any, any>[][] = [];
|
|
280
|
+
if (!this.state.fields) {
|
|
281
|
+
return rows;
|
|
268
282
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
283
|
+
|
|
284
|
+
if (this.props.fieldLayout) {
|
|
285
|
+
if (typeof this.props.fieldLayout[0] === 'string') {
|
|
286
|
+
for (let i = 0; i < this.props.fieldLayout.length; i++) {
|
|
287
|
+
const fieldPropertyName = this.props.fieldLayout[i] as string;
|
|
288
|
+
const fieldComponent = this.state.fields[fieldPropertyName];
|
|
289
|
+
fieldComponent.field.layout = { row: i, width: 12 };
|
|
290
|
+
rows.push([fieldComponent]);
|
|
291
|
+
}
|
|
292
|
+
} else {
|
|
293
|
+
for (let i = 0; i < this.props.fieldLayout.length; i++) {
|
|
294
|
+
const row = this.props.fieldLayout[i] as string[];
|
|
295
|
+
const columns = row.length;
|
|
296
|
+
if (columns > 6) {
|
|
297
|
+
throw new Error(
|
|
298
|
+
`When using FormProps.fieldLayout, the maximum number of fields per row is 6, provided: ${columns}. For more granular layout control use Field.layout`
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const currentRow: FieldComponent<any, any>[] = [];
|
|
303
|
+
for (const fieldPropertyName of row) {
|
|
304
|
+
const fieldComponent = this.state.fields[fieldPropertyName];
|
|
305
|
+
fieldComponent.field.layout = { row: i, width: columns == 5 ? 2 : ((12 / columns) as 1) };
|
|
306
|
+
currentRow.push(fieldComponent);
|
|
307
|
+
}
|
|
308
|
+
rows.push(currentRow);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
} else {
|
|
312
|
+
for (const fieldPropertyName in this.state.fields) {
|
|
313
|
+
const fieldComponent: FieldComponent<any, any> = this.state.fields[fieldPropertyName];
|
|
314
|
+
const field = fieldComponent.field;
|
|
315
|
+
if (!field.layout) {
|
|
316
|
+
throw new Error(
|
|
317
|
+
`Unless using FormProps.fieldLayout, Field.layout must be provided; layout not provided for field: ${field.name}`
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (typeof rows[field.layout.row] === 'undefined') {
|
|
322
|
+
rows[field.layout.row] = [];
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (field.layout.column && rows[field.layout.row].length >= field.layout.column) {
|
|
326
|
+
rows[field.layout.row].splice(field.layout.column - 1, 0, fieldComponent);
|
|
299
327
|
} else {
|
|
300
|
-
|
|
301
|
-
const fieldComponent: FieldComponent<any, any> = this.state.fields[fieldPropertyName];
|
|
302
|
-
const field = fieldComponent.field;
|
|
303
|
-
if (!field.layout)
|
|
304
|
-
throw new Error(`Unless using FormProps.fieldLayout, Field.layout must be provided; layout not provided for field: ${field.name}`);
|
|
305
|
-
|
|
306
|
-
if (typeof rows[field.layout.row] === 'undefined')
|
|
307
|
-
rows[field.layout.row] = [];
|
|
308
|
-
|
|
309
|
-
if (field.layout.column && rows[field.layout.row].length >= field.layout.column) {
|
|
310
|
-
rows[field.layout.row].splice(field.layout.column - 1, 0, fieldComponent);
|
|
311
|
-
} else
|
|
312
|
-
rows[field.layout.row].push(fieldComponent);
|
|
313
|
-
|
|
314
|
-
const rowWidth = rows[field.layout.row].map((fieldComponent) => fieldComponent.field.layout?.width ? fieldComponent.field.layout.width as number : 0).reduce((accumulator, currentWidth) => accumulator + currentWidth);
|
|
315
|
-
if (rowWidth > 12)
|
|
316
|
-
throw new Error(`Width of row exceeds maximum width (12), row width: ${rowWidth}, row index: ${field.layout.row}`);
|
|
317
|
-
}
|
|
328
|
+
rows[field.layout.row].push(fieldComponent);
|
|
318
329
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
330
|
+
|
|
331
|
+
const rowWidth = rows[field.layout.row]
|
|
332
|
+
.map((fieldComponent) =>
|
|
333
|
+
fieldComponent.field.layout?.width ? (fieldComponent.field.layout.width as number) : 0
|
|
334
|
+
)
|
|
335
|
+
.reduce((accumulator, currentWidth) => accumulator + currentWidth);
|
|
336
|
+
if (rowWidth > 12) {
|
|
337
|
+
throw new Error(
|
|
338
|
+
`Width of row exceeds maximum width (12), row width: ${rowWidth}, row index: ${field.layout.row}`
|
|
339
|
+
);
|
|
327
340
|
}
|
|
328
|
-
|
|
329
|
-
return false;
|
|
341
|
+
}
|
|
330
342
|
}
|
|
331
|
-
|
|
332
|
-
private Progress() {
|
|
333
|
-
if (!this.state.progress || !this.state.progress.visible)
|
|
334
|
-
return null;
|
|
335
343
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
<Container>
|
|
345
|
-
<LinearProgress variant='indeterminate' color='primary' />
|
|
346
|
-
</Container>
|
|
347
|
-
</Grid>
|
|
348
|
-
);
|
|
344
|
+
return rows;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
private isFieldRowVisible(fieldComponents: FieldComponent<any, any>[]): boolean {
|
|
348
|
+
for (const fieldComponent of fieldComponents) {
|
|
349
|
+
if (!fieldComponent.field.accessibility || !fieldComponent.field.accessibility?.hidden) {
|
|
350
|
+
return true;
|
|
351
|
+
}
|
|
349
352
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
353
|
+
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
private Progress() {
|
|
358
|
+
if (!this.state.progress || !this.state.progress.visible) {
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return (
|
|
363
|
+
<Grid container xs={12} justifyContent='center' alignItems='center' spacing={2}>
|
|
364
|
+
<Container>
|
|
365
|
+
<LinearProgress variant='indeterminate' color='primary' />
|
|
366
|
+
</Container>
|
|
367
|
+
</Grid>
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
private Buttons() {
|
|
372
|
+
return (
|
|
373
|
+
<Grid
|
|
374
|
+
container
|
|
375
|
+
direction='row'
|
|
376
|
+
justifyContent='flex-end'
|
|
377
|
+
alignItems='center'
|
|
378
|
+
xs={12}
|
|
379
|
+
sx={(theme) => ({
|
|
380
|
+
marginTop: theme.spacing(2),
|
|
381
|
+
marginBottom: theme.spacing(1),
|
|
382
|
+
})}
|
|
383
|
+
>
|
|
384
|
+
{Object.keys(this.props.buttons)
|
|
385
|
+
.map((buttonPropertyName) => this.props.buttons[buttonPropertyName])
|
|
386
|
+
.filter((button) => {
|
|
387
|
+
if (button.accessibility?.hidden) {
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return true;
|
|
392
|
+
})
|
|
393
|
+
.map((button, key) => {
|
|
394
|
+
return (
|
|
395
|
+
<Grid
|
|
396
|
+
key={key}
|
|
359
397
|
sx={(theme) => ({
|
|
360
|
-
|
|
361
|
-
marginBottom: theme.spacing(1),
|
|
398
|
+
marginLeft: theme.spacing(1),
|
|
362
399
|
})}
|
|
363
|
-
|
|
364
|
-
{
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
</IconButton>
|
|
385
|
-
:
|
|
386
|
-
<Button
|
|
387
|
-
color={button.style.color}
|
|
388
|
-
variant={button.style.variant ? button.style.variant : 'contained'}
|
|
389
|
-
disabled={button.accessibility?.disabled}
|
|
390
|
-
onClick={event => this.onClick(button)}
|
|
391
|
-
>
|
|
392
|
-
{button.name}
|
|
393
|
-
</Button>
|
|
394
|
-
}
|
|
395
|
-
</Grid>
|
|
396
|
-
)
|
|
397
|
-
})
|
|
398
|
-
}
|
|
399
|
-
</Grid>
|
|
400
|
-
);
|
|
401
|
-
}
|
|
400
|
+
>
|
|
401
|
+
{button.style.icon ? (
|
|
402
|
+
<IconButton disabled={button.accessibility?.disabled} onClick={(event: any) => this.onClick(button)}>
|
|
403
|
+
<button.style.icon />
|
|
404
|
+
</IconButton>
|
|
405
|
+
) : (
|
|
406
|
+
<Button
|
|
407
|
+
color={button.style.color}
|
|
408
|
+
variant={button.style.variant ? button.style.variant : 'contained'}
|
|
409
|
+
disabled={button.accessibility?.disabled}
|
|
410
|
+
onClick={(event) => this.onClick(button)}
|
|
411
|
+
>
|
|
412
|
+
{button.name}
|
|
413
|
+
</Button>
|
|
414
|
+
)}
|
|
415
|
+
</Grid>
|
|
416
|
+
);
|
|
417
|
+
})}
|
|
418
|
+
</Grid>
|
|
419
|
+
);
|
|
420
|
+
}
|
|
402
421
|
}
|
|
403
422
|
|
|
404
423
|
type FormType = <F extends Fields, B extends FormButtons<F>>(props: Omit<FormProps<F, B>, 'classes'>) => JSX.Element;
|
|
405
|
-
export const Form = withRouter(FormComponent) as FormType;
|
|
424
|
+
export const Form = withRouter(FormComponent) as FormType;
|