-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathwidget-renderer.tsx
127 lines (106 loc) · 3.06 KB
/
widget-renderer.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
import React from 'react';
import { Box, Text } from '@chakra-ui/react';
import { usePluginConfig } from '../context/plugin-config';
import { ErrorBox } from './error-box';
import { SchemaField } from '../schema/types';
interface WidgetProps {
pointer: string;
field: SchemaField;
isRequired?: boolean;
}
/**
* Renders the widget for a field.
* @param props.pointer The path to the field in the form data
* @param props.field The field schema to render
* @param props.isRequired Whether the field is required
*/
export function WidgetRenderer(props: WidgetProps) {
const { pointer, field, isRequired } = props;
const config = usePluginConfig();
const renderWidget = (widget: string) => {
const Widget = config['ui:widget'][widget];
return (
<WidgetErrorBoundary field={field} widgetName={widget} pointer={pointer}>
{Widget ? (
<Widget pointer={pointer} field={field} isRequired={isRequired} />
) : (
<ErrorBox>Widget "{widget}" not found</ErrorBox>
)}
</WidgetErrorBoundary>
);
};
// Explicitly defined widget
if (field['ui:widget']) {
return renderWidget(field['ui:widget']);
}
if (field.type === 'array') {
if (field.items.type === 'string' && field.items.enum) {
return renderWidget('checkbox');
}
if (['string', 'number'].includes(field.items.type)) {
return renderWidget('array:string');
}
return renderWidget('array');
}
if (field.type === 'root' || field.type === 'object') {
return renderWidget('object');
}
if (field.type === 'string' && field.enum) {
return renderWidget('radio');
}
if (field.type === 'json') {
return renderWidget('json');
}
if (field.type === 'number') {
return renderWidget('number');
}
return renderWidget('text');
}
interface WidgetErrorBoundaryProps {
children: React.ReactNode;
field: SchemaField;
widgetName: string;
pointer: string;
}
interface WidgetErrorBoundaryState {
error: Error | null;
}
class WidgetErrorBoundary extends React.Component<
WidgetErrorBoundaryProps,
WidgetErrorBoundaryState
> {
constructor(props: WidgetErrorBoundaryProps) {
super(props);
this.state = { error: null };
}
static getDerivedStateFromError(error: Error): WidgetErrorBoundaryState {
return { error };
}
render() {
if (this.state.error) {
return (
<ErrorBox color='base.500' alignItems='left' p={4}>
<Text textTransform='uppercase' color='red.500'>
💔 Error rendering widget ({this.props.widgetName})
</Text>
<Text>
{this.state.error.message || 'Something is wrong with this widget'}
</Text>
<Box
as='pre'
bg='base.100'
borderRadius='md'
p={2}
fontSize='small'
maxH={64}
overflow='auto'
>
@.{this.props.pointer} <br />
<code>{JSON.stringify(this.props.field, null, 2)}</code>
</Box>
</ErrorBox>
);
}
return this.props.children;
}
}