Skip to content

Commit a6fa3c8

Browse files
Make material renderers aware of input variant in theme (#2182)
Extend the react material renderers to be aware of MUI's input variant in the theme. - Extend input controls to be aware of the configured variant and use it - Extend input renderers to set the variant on the form control - Extend react material example with a variant selection dropdown Fix #1797
1 parent 694020b commit a6fa3c8

20 files changed

+274
-97
lines changed

packages/examples-react/src/App.tsx

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ type AppProps = {
3939
examples: ExampleDescription[];
4040
cells: JsonFormsCellRendererRegistryEntry[];
4141
renderers: JsonFormsRendererRegistryEntry[];
42+
Wrapper?: React.JSXElementConstructor<any>;
4243
};
4344

4445
type Action = {
@@ -69,7 +70,12 @@ const getProps = (
6970
};
7071
};
7172

72-
const App = ({ examples, cells, renderers }: AppProps) => {
73+
const App = ({
74+
examples,
75+
cells,
76+
renderers,
77+
Wrapper = React.Fragment,
78+
}: AppProps) => {
7379
const [currentExample, setExample] = useState<ExampleDescription>(
7480
examples[0]
7581
);
@@ -88,7 +94,7 @@ const App = ({ examples, cells, renderers }: AppProps) => {
8894
[exampleProps.uischema]
8995
);
9096

91-
const actions: Action[] = currentExample.actions;
97+
const actions: Action[] = currentExample.actions ?? [];
9298

9399
useEffect(() => {
94100
const hash = window.location.hash.replace('#', '');
@@ -192,11 +198,13 @@ const App = ({ examples, cells, renderers }: AppProps) => {
192198
))}
193199
</div>
194200
<div className='demo'>
195-
<JsonForms
196-
key={currentIndex}
197-
{...exampleProps}
198-
onChange={({ data }) => changeData(data)}
199-
/>
201+
<Wrapper>
202+
<JsonForms
203+
key={currentIndex}
204+
{...exampleProps}
205+
onChange={({ data }) => changeData(data)}
206+
/>
207+
</Wrapper>
200208
</div>
201209
</div>
202210
</div>

packages/examples-react/src/index.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,17 @@ import { getExamples } from '@jsonforms/examples';
3030

3131
export const renderExample = (
3232
renderers: { tester: RankedTester; renderer: any }[],
33-
cells: { tester: RankedTester; cell: any }[]
33+
cells: { tester: RankedTester; cell: any }[],
34+
Wrapper?: React.JSXElementConstructor<any>
3435
) => {
3536
const examples = getExamples();
3637
ReactDOM.render(
37-
<App examples={examples} renderers={renderers} cells={cells} />,
38+
<App
39+
examples={examples}
40+
renderers={renderers}
41+
cells={cells}
42+
Wrapper={Wrapper}
43+
/>,
3844
document.getElementById('root')
3945
);
4046
};

packages/material-renderers/example/index.ts

Lines changed: 0 additions & 28 deletions
This file was deleted.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
The MIT License
3+
4+
Copyright (c) 2017-2019 EclipseSource Munich
5+
https://github.com/eclipsesource/jsonforms
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights
10+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
copies of the Software, and to permit persons to whom the Software is
12+
furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in
15+
all copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
THE SOFTWARE.
24+
*/
25+
26+
import React from 'react';
27+
import {
28+
Divider,
29+
FormControl,
30+
InputLabel,
31+
MenuItem,
32+
Select,
33+
SelectChangeEvent,
34+
Stack,
35+
TextFieldProps,
36+
ThemeProvider,
37+
createTheme,
38+
} from '@mui/material';
39+
import { renderExample } from '../../examples-react/src/index';
40+
import { materialRenderers, materialCells } from '../src';
41+
42+
const MuiWrapper = ({ children }: React.PropsWithChildren<unknown>) => {
43+
const [variant, setVariant] =
44+
React.useState<TextFieldProps['variant']>('standard');
45+
46+
const handleVariantChange = (event: SelectChangeEvent<unknown>) => {
47+
setVariant(event.target.value as TextFieldProps['variant']);
48+
};
49+
50+
const theme = React.useMemo(() => {
51+
return createTheme({
52+
components: {
53+
MuiTextField: {
54+
defaultProps: {
55+
variant,
56+
},
57+
},
58+
MuiSelect: {
59+
defaultProps: {
60+
variant,
61+
},
62+
},
63+
// avoid jammed look of input fields when variant is not 'standard'
64+
...(variant !== 'standard'
65+
? {
66+
MuiFormControl: {
67+
styleOverrides: {
68+
root: {
69+
marginTop: '8px',
70+
},
71+
},
72+
},
73+
}
74+
: {}),
75+
},
76+
});
77+
}, [variant]);
78+
79+
const label = 'TextField variant';
80+
81+
return (
82+
<ThemeProvider theme={theme}>
83+
<Stack spacing={2}>
84+
<FormControl sx={{ width: 200 }} variant='outlined'>
85+
<InputLabel>{label}</InputLabel>
86+
<Select value={variant} label={label} onChange={handleVariantChange}>
87+
<MenuItem value='standard'>Standard</MenuItem>
88+
<MenuItem value='outlined'>Outlined</MenuItem>
89+
<MenuItem value='filled'>Filled</MenuItem>
90+
</Select>
91+
</FormControl>
92+
<Divider />
93+
{children}
94+
</Stack>
95+
</ThemeProvider>
96+
);
97+
};
98+
99+
renderExample(materialRenderers, materialCells, MuiWrapper);

packages/material-renderers/rollup.example.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ function cjsCompatPlugin() {
4343
* @type {import('rollup').RollupOptions}
4444
*/
4545
const config = {
46-
input: 'example/index.ts',
46+
input: 'example/index.tsx',
4747
output: {
4848
file: 'example/dist/bundle.js',
4949
format: 'iife',

packages/material-renderers/src/cells/MaterialDateCell.tsx

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,37 @@ import {
3131
WithClassname,
3232
} from '@jsonforms/core';
3333
import { withJsonFormsCellProps } from '@jsonforms/react';
34-
import Input from '@mui/material/Input';
3534
import merge from 'lodash/merge';
35+
import { useInputComponent, WithInputProps } from '../util';
3636

37-
export const MaterialDateCell = (props: CellProps & WithClassname) => {
38-
const { data, className, id, enabled, uischema, path, handleChange, config } =
39-
props;
37+
export const MaterialDateCell = (
38+
props: CellProps & WithClassname & WithInputProps
39+
) => {
40+
const {
41+
data,
42+
className,
43+
id,
44+
enabled,
45+
uischema,
46+
path,
47+
handleChange,
48+
config,
49+
label,
50+
} = props;
4051

52+
const InputComponent = useInputComponent();
4153
const appliedUiSchemaOptions = merge({}, config, uischema.options);
4254

4355
return (
44-
<Input
56+
<InputComponent
4557
type='date'
4658
value={data || ''}
47-
onChange={(ev) => handleChange(path, ev.target.value)}
59+
onChange={(ev: React.ChangeEvent<HTMLInputElement>) =>
60+
handleChange(path, ev.target.value)
61+
}
4862
className={className}
4963
id={id}
64+
label={label}
5065
disabled={!enabled}
5166
autoFocus={appliedUiSchemaOptions.focus}
5267
fullWidth={true}

packages/material-renderers/src/controls/MaterialAnyOfStringOrEnumControl.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ import {
3535
WithClassname,
3636
} from '@jsonforms/core';
3737
import { Control, withJsonFormsControlProps } from '@jsonforms/react';
38-
import { Input, InputBaseComponentProps } from '@mui/material';
38+
import { InputBaseComponentProps } from '@mui/material';
3939
import merge from 'lodash/merge';
4040
import React, { useMemo } from 'react';
41-
import { useDebouncedChange } from '../util';
41+
import { useDebouncedChange, useInputComponent, WithInputProps } from '../util';
4242
import { MaterialInputControl } from './MaterialInputControl';
4343

4444
const findEnumSchema = (schemas: JsonSchema[]) =>
@@ -48,7 +48,9 @@ const findEnumSchema = (schemas: JsonSchema[]) =>
4848
const findTextSchema = (schemas: JsonSchema[]) =>
4949
schemas.find((s) => s.type === 'string' && s.enum === undefined);
5050

51-
const MuiAutocompleteInputText = (props: EnumCellProps & WithClassname) => {
51+
const MuiAutocompleteInputText = (
52+
props: EnumCellProps & WithClassname & WithInputProps
53+
) => {
5254
const {
5355
data,
5456
config,
@@ -60,7 +62,9 @@ const MuiAutocompleteInputText = (props: EnumCellProps & WithClassname) => {
6062
path,
6163
handleChange,
6264
schema,
65+
label,
6366
} = props;
67+
const InputComponent = useInputComponent();
6468
const enumSchema = findEnumSchema(schema.anyOf);
6569
const stringSchema = findTextSchema(schema.anyOf);
6670
const maxLength = stringSchema.maxLength;
@@ -94,12 +98,13 @@ const MuiAutocompleteInputText = (props: EnumCellProps & WithClassname) => {
9498
</datalist>
9599
);
96100
return (
97-
<Input
101+
<InputComponent
98102
type='text'
99103
value={inputText}
100104
onChange={onChange}
101105
className={className}
102106
id={id}
107+
label={label}
103108
disabled={!enabled}
104109
autoFocus={appliedUiSchemaOptions.focus}
105110
fullWidth={!appliedUiSchemaOptions.trim || maxLength === undefined}

packages/material-renderers/src/controls/MaterialDateControl.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@ export const MaterialDateControl = (props: ControlProps) => {
110110
InputLabelProps: data ? { shrink: true } : undefined,
111111
onFocus: onFocus,
112112
onBlur: onBlur,
113-
variant: 'standard',
114113
},
115114
}}
116115
/>

packages/material-renderers/src/controls/MaterialDateTimeControl.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ export const MaterialDateTimeControl = (props: ControlProps) => {
118118
InputLabelProps: data ? { shrink: true } : undefined,
119119
onFocus: onFocus,
120120
onBlur: onBlur,
121-
variant: 'standard',
122121
},
123122
}}
124123
/>

packages/material-renderers/src/controls/MaterialInputControl.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import {
3131

3232
import { Hidden, InputLabel, FormControl, FormHelperText } from '@mui/material';
3333
import merge from 'lodash/merge';
34-
import { useFocus } from '../util';
34+
import { useFocus, useInputVariant } from '../util';
3535

3636
export interface WithInput {
3737
input: any;
@@ -50,6 +50,7 @@ export const MaterialInputControl = (props: ControlProps & WithInput) => {
5050
config,
5151
input,
5252
} = props;
53+
const variant = useInputVariant();
5354
const isValid = errors.length === 0;
5455
const appliedUiSchemaOptions = merge({}, config, uischema.options);
5556

@@ -74,8 +75,8 @@ export const MaterialInputControl = (props: ControlProps & WithInput) => {
7475
fullWidth={!appliedUiSchemaOptions.trim}
7576
onFocus={onFocus}
7677
onBlur={onBlur}
78+
variant={variant}
7779
id={id}
78-
variant={'standard'}
7980
>
8081
<InputLabel
8182
htmlFor={id + '-input'}

0 commit comments

Comments
 (0)