Skip to content

Commit

Permalink
Make material renderers aware of input variant in theme (#2182)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
sebastianfrey authored Oct 9, 2023
1 parent 694020b commit a6fa3c8
Show file tree
Hide file tree
Showing 20 changed files with 274 additions and 97 deletions.
22 changes: 15 additions & 7 deletions packages/examples-react/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type AppProps = {
examples: ExampleDescription[];
cells: JsonFormsCellRendererRegistryEntry[];
renderers: JsonFormsRendererRegistryEntry[];
Wrapper?: React.JSXElementConstructor<any>;
};

type Action = {
Expand Down Expand Up @@ -69,7 +70,12 @@ const getProps = (
};
};

const App = ({ examples, cells, renderers }: AppProps) => {
const App = ({
examples,
cells,
renderers,
Wrapper = React.Fragment,
}: AppProps) => {
const [currentExample, setExample] = useState<ExampleDescription>(
examples[0]
);
Expand All @@ -88,7 +94,7 @@ const App = ({ examples, cells, renderers }: AppProps) => {
[exampleProps.uischema]
);

const actions: Action[] = currentExample.actions;
const actions: Action[] = currentExample.actions ?? [];

useEffect(() => {
const hash = window.location.hash.replace('#', '');
Expand Down Expand Up @@ -192,11 +198,13 @@ const App = ({ examples, cells, renderers }: AppProps) => {
))}
</div>
<div className='demo'>
<JsonForms
key={currentIndex}
{...exampleProps}
onChange={({ data }) => changeData(data)}
/>
<Wrapper>
<JsonForms
key={currentIndex}
{...exampleProps}
onChange={({ data }) => changeData(data)}
/>
</Wrapper>
</div>
</div>
</div>
Expand Down
10 changes: 8 additions & 2 deletions packages/examples-react/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,17 @@ import { getExamples } from '@jsonforms/examples';

export const renderExample = (
renderers: { tester: RankedTester; renderer: any }[],
cells: { tester: RankedTester; cell: any }[]
cells: { tester: RankedTester; cell: any }[],
Wrapper?: React.JSXElementConstructor<any>
) => {
const examples = getExamples();
ReactDOM.render(
<App examples={examples} renderers={renderers} cells={cells} />,
<App
examples={examples}
renderers={renderers}
cells={cells}
Wrapper={Wrapper}
/>,
document.getElementById('root')
);
};
28 changes: 0 additions & 28 deletions packages/material-renderers/example/index.ts

This file was deleted.

99 changes: 99 additions & 0 deletions packages/material-renderers/example/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
The MIT License
Copyright (c) 2017-2019 EclipseSource Munich
https://github.com/eclipsesource/jsonforms
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

import React from 'react';
import {
Divider,
FormControl,
InputLabel,
MenuItem,
Select,
SelectChangeEvent,
Stack,
TextFieldProps,
ThemeProvider,
createTheme,
} from '@mui/material';
import { renderExample } from '../../examples-react/src/index';
import { materialRenderers, materialCells } from '../src';

const MuiWrapper = ({ children }: React.PropsWithChildren<unknown>) => {
const [variant, setVariant] =
React.useState<TextFieldProps['variant']>('standard');

const handleVariantChange = (event: SelectChangeEvent<unknown>) => {
setVariant(event.target.value as TextFieldProps['variant']);
};

const theme = React.useMemo(() => {
return createTheme({
components: {
MuiTextField: {
defaultProps: {
variant,
},
},
MuiSelect: {
defaultProps: {
variant,
},
},
// avoid jammed look of input fields when variant is not 'standard'
...(variant !== 'standard'
? {
MuiFormControl: {
styleOverrides: {
root: {
marginTop: '8px',
},
},
},
}
: {}),
},
});
}, [variant]);

const label = 'TextField variant';

return (
<ThemeProvider theme={theme}>
<Stack spacing={2}>
<FormControl sx={{ width: 200 }} variant='outlined'>
<InputLabel>{label}</InputLabel>
<Select value={variant} label={label} onChange={handleVariantChange}>
<MenuItem value='standard'>Standard</MenuItem>
<MenuItem value='outlined'>Outlined</MenuItem>
<MenuItem value='filled'>Filled</MenuItem>
</Select>
</FormControl>
<Divider />
{children}
</Stack>
</ThemeProvider>
);
};

renderExample(materialRenderers, materialCells, MuiWrapper);
2 changes: 1 addition & 1 deletion packages/material-renderers/rollup.example.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function cjsCompatPlugin() {
* @type {import('rollup').RollupOptions}
*/
const config = {
input: 'example/index.ts',
input: 'example/index.tsx',
output: {
file: 'example/dist/bundle.js',
format: 'iife',
Expand Down
27 changes: 21 additions & 6 deletions packages/material-renderers/src/cells/MaterialDateCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,37 @@ import {
WithClassname,
} from '@jsonforms/core';
import { withJsonFormsCellProps } from '@jsonforms/react';
import Input from '@mui/material/Input';
import merge from 'lodash/merge';
import { useInputComponent, WithInputProps } from '../util';

export const MaterialDateCell = (props: CellProps & WithClassname) => {
const { data, className, id, enabled, uischema, path, handleChange, config } =
props;
export const MaterialDateCell = (
props: CellProps & WithClassname & WithInputProps
) => {
const {
data,
className,
id,
enabled,
uischema,
path,
handleChange,
config,
label,
} = props;

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

return (
<Input
<InputComponent
type='date'
value={data || ''}
onChange={(ev) => handleChange(path, ev.target.value)}
onChange={(ev: React.ChangeEvent<HTMLInputElement>) =>
handleChange(path, ev.target.value)
}
className={className}
id={id}
label={label}
disabled={!enabled}
autoFocus={appliedUiSchemaOptions.focus}
fullWidth={true}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ import {
WithClassname,
} from '@jsonforms/core';
import { Control, withJsonFormsControlProps } from '@jsonforms/react';
import { Input, InputBaseComponentProps } from '@mui/material';
import { InputBaseComponentProps } from '@mui/material';
import merge from 'lodash/merge';
import React, { useMemo } from 'react';
import { useDebouncedChange } from '../util';
import { useDebouncedChange, useInputComponent, WithInputProps } from '../util';
import { MaterialInputControl } from './MaterialInputControl';

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

const MuiAutocompleteInputText = (props: EnumCellProps & WithClassname) => {
const MuiAutocompleteInputText = (
props: EnumCellProps & WithClassname & WithInputProps
) => {
const {
data,
config,
Expand All @@ -60,7 +62,9 @@ const MuiAutocompleteInputText = (props: EnumCellProps & WithClassname) => {
path,
handleChange,
schema,
label,
} = props;
const InputComponent = useInputComponent();
const enumSchema = findEnumSchema(schema.anyOf);
const stringSchema = findTextSchema(schema.anyOf);
const maxLength = stringSchema.maxLength;
Expand Down Expand Up @@ -94,12 +98,13 @@ const MuiAutocompleteInputText = (props: EnumCellProps & WithClassname) => {
</datalist>
);
return (
<Input
<InputComponent
type='text'
value={inputText}
onChange={onChange}
className={className}
id={id}
label={label}
disabled={!enabled}
autoFocus={appliedUiSchemaOptions.focus}
fullWidth={!appliedUiSchemaOptions.trim || maxLength === undefined}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ export const MaterialDateControl = (props: ControlProps) => {
InputLabelProps: data ? { shrink: true } : undefined,
onFocus: onFocus,
onBlur: onBlur,
variant: 'standard',
},
}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ export const MaterialDateTimeControl = (props: ControlProps) => {
InputLabelProps: data ? { shrink: true } : undefined,
onFocus: onFocus,
onBlur: onBlur,
variant: 'standard',
},
}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {

import { Hidden, InputLabel, FormControl, FormHelperText } from '@mui/material';
import merge from 'lodash/merge';
import { useFocus } from '../util';
import { useFocus, useInputVariant } from '../util';

export interface WithInput {
input: any;
Expand All @@ -50,6 +50,7 @@ export const MaterialInputControl = (props: ControlProps & WithInput) => {
config,
input,
} = props;
const variant = useInputVariant();
const isValid = errors.length === 0;
const appliedUiSchemaOptions = merge({}, config, uischema.options);

Expand All @@ -74,8 +75,8 @@ export const MaterialInputControl = (props: ControlProps & WithInput) => {
fullWidth={!appliedUiSchemaOptions.trim}
onFocus={onFocus}
onBlur={onBlur}
variant={variant}
id={id}
variant={'standard'}
>
<InputLabel
htmlFor={id + '-input'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ export const MaterialTimeControl = (props: ControlProps) => {
InputLabelProps: data ? { shrink: true } : undefined,
onFocus: onFocus,
onBlur: onBlur,
variant: 'standard',
},
}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ export const MuiAutocomplete = (
return (
<TextField
label={label}
variant={'standard'}
type='text'
inputProps={params.inputProps}
inputRef={params.InputProps.ref}
Expand Down
Loading

0 comments on commit a6fa3c8

Please sign in to comment.