@rjsf/mui 6.4.1 → 6.5.0

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.
Files changed (93) hide show
  1. package/README.md +25 -0
  2. package/dist/index.cjs +353 -214
  3. package/dist/index.cjs.map +4 -4
  4. package/dist/mui.esm.js +354 -185
  5. package/dist/mui.esm.js.map +4 -4
  6. package/dist/mui.umd.js +293 -165
  7. package/lib/AddButton/AddButton.js +12 -2
  8. package/lib/AddButton/AddButton.js.map +1 -1
  9. package/lib/ArrayFieldItemTemplate/ArrayFieldItemTemplate.d.ts +22 -1
  10. package/lib/ArrayFieldItemTemplate/ArrayFieldItemTemplate.js +3 -1
  11. package/lib/ArrayFieldItemTemplate/ArrayFieldItemTemplate.js.map +1 -1
  12. package/lib/ArrayFieldTemplate/ArrayFieldTemplate.d.ts +20 -1
  13. package/lib/ArrayFieldTemplate/ArrayFieldTemplate.js +3 -1
  14. package/lib/ArrayFieldTemplate/ArrayFieldTemplate.js.map +1 -1
  15. package/lib/BaseInputTemplate/BaseInputTemplate.d.ts +17 -1
  16. package/lib/BaseInputTemplate/BaseInputTemplate.js +9 -4
  17. package/lib/BaseInputTemplate/BaseInputTemplate.js.map +1 -1
  18. package/lib/CheckboxWidget/CheckboxWidget.d.ts +13 -1
  19. package/lib/CheckboxWidget/CheckboxWidget.js +3 -1
  20. package/lib/CheckboxWidget/CheckboxWidget.js.map +1 -1
  21. package/lib/CheckboxesWidget/CheckboxesWidget.d.ts +17 -2
  22. package/lib/CheckboxesWidget/CheckboxesWidget.js +12 -7
  23. package/lib/CheckboxesWidget/CheckboxesWidget.js.map +1 -1
  24. package/lib/DescriptionField/DescriptionField.d.ts +10 -1
  25. package/lib/DescriptionField/DescriptionField.js +6 -1
  26. package/lib/DescriptionField/DescriptionField.js.map +1 -1
  27. package/lib/ErrorList/ErrorList.d.ts +29 -2
  28. package/lib/ErrorList/ErrorList.js +7 -4
  29. package/lib/ErrorList/ErrorList.js.map +1 -1
  30. package/lib/FieldErrorTemplate/FieldErrorTemplate.d.ts +16 -1
  31. package/lib/FieldErrorTemplate/FieldErrorTemplate.js +8 -4
  32. package/lib/FieldErrorTemplate/FieldErrorTemplate.js.map +1 -1
  33. package/lib/FieldHelpTemplate/FieldHelpTemplate.d.ts +10 -1
  34. package/lib/FieldHelpTemplate/FieldHelpTemplate.js +6 -2
  35. package/lib/FieldHelpTemplate/FieldHelpTemplate.js.map +1 -1
  36. package/lib/FieldTemplate/FieldTemplate.d.ts +13 -1
  37. package/lib/FieldTemplate/FieldTemplate.js +3 -1
  38. package/lib/FieldTemplate/FieldTemplate.js.map +1 -1
  39. package/lib/IconButton/IconButton.js +12 -2
  40. package/lib/IconButton/IconButton.js.map +1 -1
  41. package/lib/MultiSchemaFieldTemplate/MultiSchemaFieldTemplate.d.ts +13 -1
  42. package/lib/MultiSchemaFieldTemplate/MultiSchemaFieldTemplate.js +6 -2
  43. package/lib/MultiSchemaFieldTemplate/MultiSchemaFieldTemplate.js.map +1 -1
  44. package/lib/ObjectFieldTemplate/ObjectFieldTemplate.d.ts +16 -1
  45. package/lib/ObjectFieldTemplate/ObjectFieldTemplate.js +4 -2
  46. package/lib/ObjectFieldTemplate/ObjectFieldTemplate.js.map +1 -1
  47. package/lib/OptionalDataControlsTemplate/OptionalDataControlsTemplate.js +3 -3
  48. package/lib/OptionalDataControlsTemplate/OptionalDataControlsTemplate.js.map +1 -1
  49. package/lib/RadioWidget/RadioWidget.d.ts +17 -2
  50. package/lib/RadioWidget/RadioWidget.js +13 -9
  51. package/lib/RadioWidget/RadioWidget.js.map +1 -1
  52. package/lib/RangeWidget/RangeWidget.d.ts +10 -1
  53. package/lib/RangeWidget/RangeWidget.js +3 -1
  54. package/lib/RangeWidget/RangeWidget.js.map +1 -1
  55. package/lib/SelectWidget/SelectWidget.d.ts +14 -3
  56. package/lib/SelectWidget/SelectWidget.js +26 -19
  57. package/lib/SelectWidget/SelectWidget.js.map +1 -1
  58. package/lib/SubmitButton/SubmitButton.d.ts +13 -1
  59. package/lib/SubmitButton/SubmitButton.js +5 -2
  60. package/lib/SubmitButton/SubmitButton.js.map +1 -1
  61. package/lib/TitleField/TitleField.d.ts +24 -2
  62. package/lib/TitleField/TitleField.js +9 -4
  63. package/lib/TitleField/TitleField.js.map +1 -1
  64. package/lib/WrapIfAdditionalTemplate/WrapIfAdditionalTemplate.d.ts +16 -1
  65. package/lib/WrapIfAdditionalTemplate/WrapIfAdditionalTemplate.js +7 -2
  66. package/lib/WrapIfAdditionalTemplate/WrapIfAdditionalTemplate.js.map +1 -1
  67. package/lib/tsconfig.tsbuildinfo +1 -1
  68. package/lib/util.d.ts +9 -0
  69. package/lib/util.js +24 -0
  70. package/lib/util.js.map +1 -0
  71. package/package.json +7 -7
  72. package/src/AddButton/AddButton.tsx +21 -3
  73. package/src/ArrayFieldItemTemplate/ArrayFieldItemTemplate.tsx +39 -9
  74. package/src/ArrayFieldTemplate/ArrayFieldTemplate.tsx +30 -8
  75. package/src/BaseInputTemplate/BaseInputTemplate.tsx +29 -5
  76. package/src/CheckboxWidget/CheckboxWidget.tsx +20 -2
  77. package/src/CheckboxesWidget/CheckboxesWidget.tsx +51 -23
  78. package/src/DescriptionField/DescriptionField.tsx +25 -3
  79. package/src/ErrorList/ErrorList.tsx +52 -15
  80. package/src/FieldErrorTemplate/FieldErrorTemplate.tsx +34 -8
  81. package/src/FieldHelpTemplate/FieldHelpTemplate.tsx +30 -3
  82. package/src/FieldTemplate/FieldTemplate.tsx +26 -4
  83. package/src/IconButton/IconButton.tsx +21 -2
  84. package/src/MultiSchemaFieldTemplate/MultiSchemaFieldTemplate.tsx +28 -6
  85. package/src/ObjectFieldTemplate/ObjectFieldTemplate.tsx +25 -5
  86. package/src/OptionalDataControlsTemplate/OptionalDataControlsTemplate.tsx +3 -1
  87. package/src/RadioWidget/RadioWidget.tsx +43 -26
  88. package/src/RangeWidget/RangeWidget.tsx +16 -1
  89. package/src/SelectWidget/SelectWidget.tsx +71 -49
  90. package/src/SubmitButton/SubmitButton.tsx +36 -5
  91. package/src/TitleField/TitleField.tsx +54 -16
  92. package/src/WrapIfAdditionalTemplate/WrapIfAdditionalTemplate.tsx +39 -5
  93. package/src/util.ts +30 -0
@@ -1,7 +1,29 @@
1
- import ListItem from '@mui/material/ListItem';
2
- import FormHelperText from '@mui/material/FormHelperText';
3
- import List from '@mui/material/List';
4
- import { errorId, FieldErrorProps, FormContextType, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils';
1
+ import ListItem, { ListItemProps } from '@mui/material/ListItem';
2
+ import FormHelperText, { FormHelperTextProps } from '@mui/material/FormHelperText';
3
+ import List, { ListProps } from '@mui/material/List';
4
+ import {
5
+ errorId,
6
+ FieldErrorProps,
7
+ FormContextType,
8
+ GenericObjectType,
9
+ RJSFSchema,
10
+ StrictRJSFSchema,
11
+ getUiOptions,
12
+ } from '@rjsf/utils';
13
+ import { getMuiProps } from '../util';
14
+
15
+ /** Properties available for the `rjsfSlotProps` target of the FieldErrorTemplate. */
16
+ export interface FieldErrorTemplateMuiProps extends GenericObjectType {
17
+ /** RJSF-specific slot props for targeting child elements of the FieldErrorTemplate. */
18
+ rjsfSlotProps?: {
19
+ /** Props applied to the `List` container holding the errors. */
20
+ fieldErrorList?: ListProps;
21
+ /** Props applied to each `ListItem` representing an error. */
22
+ fieldErrorListItem?: ListItemProps;
23
+ /** Props applied to the `FormHelperText` displaying the actual error message. */
24
+ fieldErrorFormHelperText?: FormHelperTextProps;
25
+ };
26
+ }
5
27
 
6
28
  /** The `FieldErrorTemplate` component renders the errors local to the particular field
7
29
  *
@@ -12,18 +34,22 @@ export default function FieldErrorTemplate<
12
34
  S extends StrictRJSFSchema = RJSFSchema,
13
35
  F extends FormContextType = any,
14
36
  >(props: FieldErrorProps<T, S, F>) {
15
- const { errors = [], fieldPathId } = props;
37
+ const { errors = [], fieldPathId, uiSchema } = props;
16
38
  if (errors.length === 0) {
17
39
  return null;
18
40
  }
19
41
  const id = errorId(fieldPathId);
20
42
 
43
+ const uiOptions = getUiOptions<T, S, F>(uiSchema);
44
+ const muiProps = getMuiProps<T, S, F, FieldErrorTemplateMuiProps>(uiOptions);
45
+ const { rjsfSlotProps: muiSlotProps } = muiProps;
46
+
21
47
  return (
22
- <List id={id} dense={true} disablePadding={true}>
48
+ <List id={id} dense={true} disablePadding={true} {...muiSlotProps?.fieldErrorList}>
23
49
  {errors.map((error, i: number) => {
24
50
  return (
25
- <ListItem key={i} disableGutters={true}>
26
- <FormHelperText component='div' id={`${id}-${i}`}>
51
+ <ListItem key={i} disableGutters={true} {...muiSlotProps?.fieldErrorListItem}>
52
+ <FormHelperText component='div' id={`${id}-${i}`} {...muiSlotProps?.fieldErrorFormHelperText}>
27
53
  {error}
28
54
  </FormHelperText>
29
55
  </ListItem>
@@ -1,6 +1,24 @@
1
1
  import { RichHelp } from '@rjsf/core';
2
- import { helpId, FieldHelpProps, FormContextType, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils';
3
- import FormHelperText from '@mui/material/FormHelperText';
2
+ import {
3
+ helpId,
4
+ FieldHelpProps,
5
+ FormContextType,
6
+ RJSFSchema,
7
+ StrictRJSFSchema,
8
+ getUiOptions,
9
+ GenericObjectType,
10
+ } from '@rjsf/utils';
11
+ import FormHelperText, { FormHelperTextProps } from '@mui/material/FormHelperText';
12
+ import { getMuiProps } from '../util';
13
+
14
+ /** Properties available for the `rjsfSlotProps` target of the FieldHelpTemplate. */
15
+ export interface FieldHelpTemplateMuiProps extends GenericObjectType {
16
+ /** RJSF-specific slot props for targeting child elements of the FieldHelpTemplate. */
17
+ rjsfSlotProps?: {
18
+ /** Props applied to the `FormHelperText` used for help text. */
19
+ helpFormHelperText?: FormHelperTextProps;
20
+ };
21
+ }
4
22
 
5
23
  /** The `FieldHelpTemplate` component renders any help desired for a field
6
24
  *
@@ -16,8 +34,17 @@ export default function FieldHelpTemplate<
16
34
  return null;
17
35
  }
18
36
 
37
+ const uiOptions = getUiOptions<T, S, F>(uiSchema);
38
+ const muiProps = getMuiProps<T, S, F, FieldHelpTemplateMuiProps>(uiOptions);
39
+ const { rjsfSlotProps: muiSlotProps } = muiProps;
40
+
19
41
  return (
20
- <FormHelperText component='div' id={helpId(fieldPathId)} style={{ marginTop: '5px' }}>
42
+ <FormHelperText
43
+ component='div'
44
+ id={helpId(fieldPathId)}
45
+ style={{ marginTop: '5px' }}
46
+ {...muiSlotProps?.helpFormHelperText}
47
+ >
21
48
  <RichHelp help={help} registry={registry} uiSchema={uiSchema} />
22
49
  </FormHelperText>
23
50
  );
@@ -1,13 +1,26 @@
1
- import FormControl from '@mui/material/FormControl';
2
- import Typography from '@mui/material/Typography';
1
+ import FormControl, { FormControlProps } from '@mui/material/FormControl';
2
+ import Typography, { TypographyProps } from '@mui/material/Typography';
3
3
  import {
4
4
  FieldTemplateProps,
5
5
  FormContextType,
6
+ GenericObjectType,
6
7
  RJSFSchema,
7
8
  StrictRJSFSchema,
8
9
  getTemplate,
9
10
  getUiOptions,
10
11
  } from '@rjsf/utils';
12
+ import { getMuiProps } from '../util';
13
+
14
+ /** Properties available for the `rjsfSlotProps` target of the FieldTemplate. */
15
+ export interface FieldTemplateMuiProps extends GenericObjectType {
16
+ /** RJSF-specific slot props for targeting child elements of the FieldTemplate. */
17
+ rjsfSlotProps?: {
18
+ /** Props applied to the MUI `FormControl` wrapping the field. */
19
+ fieldFormControl?: FormControlProps;
20
+ /** Props applied to the MUI `Typography` element used for description. */
21
+ fieldTypography?: TypographyProps;
22
+ };
23
+ }
11
24
 
12
25
  /** The `FieldTemplate` component is the template used by `SchemaField` to render any field. It renders the field
13
26
  * content, (label, description, children, errors and help) inside of a `WrapIfAdditional` component.
@@ -55,6 +68,8 @@ export default function FieldTemplate<
55
68
 
56
69
  const isCheckbox = uiOptions.widget === 'checkbox';
57
70
 
71
+ const { rjsfSlotProps: muiSlotProps, ...otherMuiProps } = getMuiProps<T, S, F, FieldTemplateMuiProps>(uiOptions);
72
+
58
73
  return (
59
74
  <WrapIfAdditionalTemplate
60
75
  classNames={classNames}
@@ -73,10 +88,17 @@ export default function FieldTemplate<
73
88
  uiSchema={uiSchema}
74
89
  registry={registry}
75
90
  >
76
- <FormControl fullWidth={true} error={rawErrors.length ? true : false} required={required}>
91
+ <FormControl
92
+ fullWidth={true}
93
+ error={rawErrors.length ? true : false}
94
+ required={required}
95
+ {...muiSlotProps?.fieldFormControl}
96
+ sx={otherMuiProps.sx}
97
+ className={otherMuiProps.className}
98
+ >
77
99
  {children}
78
100
  {displayLabel && !isCheckbox && rawDescription ? (
79
- <Typography variant='caption' color='textSecondary'>
101
+ <Typography variant='caption' color='textSecondary' {...muiSlotProps?.fieldTypography}>
80
102
  {description}
81
103
  </Typography>
82
104
  ) : null}
@@ -4,7 +4,15 @@ import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward';
4
4
  import CopyIcon from '@mui/icons-material/ContentCopy';
5
5
  import RemoveIcon from '@mui/icons-material/Remove';
6
6
  import ClearIcon from '@mui/icons-material/Clear';
7
- import { FormContextType, IconButtonProps, RJSFSchema, StrictRJSFSchema, TranslatableString } from '@rjsf/utils';
7
+ import {
8
+ FormContextType,
9
+ IconButtonProps,
10
+ RJSFSchema,
11
+ StrictRJSFSchema,
12
+ TranslatableString,
13
+ getUiOptions,
14
+ } from '@rjsf/utils';
15
+ import { getMuiProps } from '../util';
8
16
 
9
17
  export default function MuiIconButton<
10
18
  T = any,
@@ -12,8 +20,19 @@ export default function MuiIconButton<
12
20
  F extends FormContextType = any,
13
21
  >(props: IconButtonProps<T, S, F>) {
14
22
  const { icon, color, uiSchema, registry, ...otherProps } = props;
23
+
24
+ const uiOptions = getUiOptions<T, S, F>(uiSchema);
25
+ const muiProps = getMuiProps<T, S, F, MuiIconButtonProps>(uiOptions, [
26
+ 'color',
27
+ 'disableFocusRipple',
28
+ 'disableRipple',
29
+ 'edge',
30
+ 'size',
31
+ 'sx',
32
+ ]);
33
+
15
34
  return (
16
- <IconButton {...otherProps} size='small' color={color as MuiIconButtonProps['color']}>
35
+ <IconButton {...muiProps} {...otherProps} size='small' color={color as MuiIconButtonProps['color']}>
17
36
  {icon}
18
37
  </IconButton>
19
38
  );
@@ -1,17 +1,39 @@
1
- import Box from '@mui/material/Box';
2
- import { FormContextType, MultiSchemaFieldTemplateProps, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils';
3
- import FormControl from '@mui/material/FormControl';
1
+ import Box, { BoxProps } from '@mui/material/Box';
2
+ import FormControl, { FormControlProps } from '@mui/material/FormControl';
3
+ import {
4
+ FormContextType,
5
+ GenericObjectType,
6
+ MultiSchemaFieldTemplateProps,
7
+ RJSFSchema,
8
+ StrictRJSFSchema,
9
+ getUiOptions,
10
+ } from '@rjsf/utils';
11
+ import { getMuiProps } from '../util';
12
+
13
+ /** Properties available for the `rjsfSlotProps` target of the MultiSchemaFieldTemplate. */
14
+ export interface MultiSchemaFieldTemplateMuiProps extends GenericObjectType {
15
+ /** RJSF-specific slot props for targeting child elements of the MultiSchemaFieldTemplate. */
16
+ rjsfSlotProps?: {
17
+ /** Props applied to the wrapper `Box` container. */
18
+ multiBox?: BoxProps;
19
+ /** Props applied to the MUI `FormControl` wrapping the selector. */
20
+ multiFormControl?: FormControlProps;
21
+ };
22
+ }
4
23
 
5
24
  export default function MultiSchemaFieldTemplate<
6
25
  T = any,
7
26
  S extends StrictRJSFSchema = RJSFSchema,
8
27
  F extends FormContextType = any,
9
28
  >(props: MultiSchemaFieldTemplateProps<T, S, F>) {
10
- const { optionSchemaField, selector } = props;
29
+ const { optionSchemaField, selector, uiSchema } = props;
30
+
31
+ const uiOptions = getUiOptions<T, S, F>(uiSchema);
32
+ const { rjsfSlotProps: muiSlotProps } = getMuiProps<T, S, F, MultiSchemaFieldTemplateMuiProps>(uiOptions);
11
33
 
12
34
  return (
13
- <Box sx={{ mb: 2 }}>
14
- <FormControl fullWidth sx={{ mb: 2 }}>
35
+ <Box sx={{ mb: 2 }} {...muiSlotProps?.multiBox}>
36
+ <FormControl fullWidth sx={{ mb: 2 }} {...muiSlotProps?.multiFormControl}>
15
37
  {selector}
16
38
  </FormControl>
17
39
  {optionSchemaField}
@@ -1,6 +1,7 @@
1
- import Grid from '@mui/material/Grid';
1
+ import Grid, { GridProps } from '@mui/material/Grid';
2
2
  import {
3
3
  FormContextType,
4
+ GenericObjectType,
4
5
  ObjectFieldTemplateProps,
5
6
  RJSFSchema,
6
7
  StrictRJSFSchema,
@@ -11,6 +12,22 @@ import {
11
12
  titleId,
12
13
  buttonId,
13
14
  } from '@rjsf/utils';
15
+ import { getMuiProps } from '../util';
16
+
17
+ /** Properties available for the `rjsfSlotProps` target of the ObjectFieldTemplate. */
18
+ export interface ObjectFieldTemplateMuiProps extends GenericObjectType {
19
+ /** RJSF-specific slot props for targeting child elements of the ObjectFieldTemplate. */
20
+ rjsfSlotProps?: {
21
+ /** Props applied to the outermost `Grid` container wrapping all object properties. */
22
+ objectGridContainer?: GridProps;
23
+ /** Props applied to the `Grid` item wrapping each individual object property. */
24
+ objectGridItem?: GridProps;
25
+ /** Props applied to the wrapper `Grid` container next to the Add Button (when expandable). */
26
+ objectAddButtonGridContainer?: GridProps;
27
+ /** Props applied to the `Grid` item containing the Add Button. */
28
+ objectAddButtonGridItem?: GridProps;
29
+ };
30
+ }
14
31
 
15
32
  /** The `ObjectFieldTemplate` is the template to use to render all the inner properties of an object along with the
16
33
  * title and description if available. If the object is expandable, then an `AddButton` is also rendered after all
@@ -50,6 +67,9 @@ export default function ObjectFieldTemplate<
50
67
  const {
51
68
  ButtonTemplates: { AddButton },
52
69
  } = registry.templates;
70
+
71
+ const { rjsfSlotProps: muiSlotProps } = getMuiProps<T, S, F, ObjectFieldTemplateMuiProps>(uiOptions);
72
+
53
73
  return (
54
74
  <>
55
75
  {title && (
@@ -72,7 +92,7 @@ export default function ObjectFieldTemplate<
72
92
  registry={registry}
73
93
  />
74
94
  )}
75
- <Grid container spacing={2} style={{ marginTop: '10px' }}>
95
+ <Grid container spacing={2} style={{ marginTop: '10px' }} {...muiSlotProps?.objectGridContainer}>
76
96
  {!showOptionalDataControlInTitle ? optionalDataControl : undefined}
77
97
  {properties.map((element, index) =>
78
98
  // Remove the <Grid> if the inner element is hidden as the <Grid>
@@ -80,15 +100,15 @@ export default function ObjectFieldTemplate<
80
100
  element.hidden ? (
81
101
  element.content
82
102
  ) : (
83
- <Grid size={{ xs: 12 }} key={index} style={{ marginBottom: '10px' }}>
103
+ <Grid size={{ xs: 12 }} key={index} style={{ marginBottom: '10px' }} {...muiSlotProps?.objectGridItem}>
84
104
  {element.content}
85
105
  </Grid>
86
106
  ),
87
107
  )}
88
108
  </Grid>
89
109
  {canExpand<T, S, F>(schema, uiSchema, formData) && (
90
- <Grid container justifyContent='flex-end'>
91
- <Grid>
110
+ <Grid container justifyContent='flex-end' {...muiSlotProps?.objectAddButtonGridContainer}>
111
+ <Grid {...muiSlotProps?.objectAddButtonGridItem}>
92
112
  <AddButton
93
113
  id={buttonId(fieldPathId, 'add')}
94
114
  className='rjsf-object-property-expand'
@@ -16,12 +16,13 @@ export default function OptionalDataControlsTemplate<
16
16
  S extends StrictRJSFSchema = RJSFSchema,
17
17
  F extends FormContextType = any,
18
18
  >(props: OptionalDataControlsTemplateProps<T, S, F>) {
19
- const { id, registry, label, onAddClick, onRemoveClick } = props;
19
+ const { id, registry, label, onAddClick, onRemoveClick, uiSchema } = props;
20
20
  if (onAddClick) {
21
21
  return (
22
22
  <IconButton
23
23
  id={id}
24
24
  registry={registry}
25
+ uiSchema={uiSchema}
25
26
  className='rjsf-add-optional-data'
26
27
  onClick={onAddClick}
27
28
  title={label}
@@ -33,6 +34,7 @@ export default function OptionalDataControlsTemplate<
33
34
  <RemoveButton
34
35
  id={id}
35
36
  registry={registry}
37
+ uiSchema={uiSchema}
36
38
  className='rjsf-remove-optional-data'
37
39
  onClick={onRemoveClick}
38
40
  title={label}
@@ -1,49 +1,61 @@
1
1
  import { FocusEvent } from 'react';
2
- import FormControlLabel from '@mui/material/FormControlLabel';
2
+ import FormControlLabel, { FormControlLabelProps } from '@mui/material/FormControlLabel';
3
3
  import FormLabel from '@mui/material/FormLabel';
4
- import Radio from '@mui/material/Radio';
5
- import RadioGroup from '@mui/material/RadioGroup';
4
+ import Radio, { RadioProps } from '@mui/material/Radio';
5
+ import RadioGroup, { RadioGroupProps } from '@mui/material/RadioGroup';
6
6
  import {
7
7
  ariaDescribedByIds,
8
- enumOptionsIndexForValue,
9
- enumOptionsValueForIndex,
8
+ enumOptionSelectedValue,
9
+ enumOptionValueDecoder,
10
+ enumOptionValueEncoder,
11
+ getOptionValueFormat,
10
12
  labelValue,
11
13
  optionId,
12
14
  FormContextType,
15
+ GenericObjectType,
13
16
  RJSFSchema,
14
17
  StrictRJSFSchema,
15
18
  WidgetProps,
16
19
  } from '@rjsf/utils';
20
+ import { getMuiProps } from '../util';
21
+
22
+ /** Properties available for the `rjsfSlotProps` target of the RadioWidget. */
23
+ export interface RadioWidgetMuiProps extends GenericObjectType {
24
+ /** RJSF-specific slot props for targeting child elements of the RadioWidget. */
25
+ rjsfSlotProps?: {
26
+ /** Props applied to the `RadioGroup` component. */
27
+ radioGroup?: RadioGroupProps;
28
+ /** Props applied to the individual `Radio` components. */
29
+ radio?: RadioProps;
30
+ /** Props applied to the `FormControlLabel` components wrapping each radio button. */
31
+ formControlLabel?: FormControlLabelProps;
32
+ };
33
+ }
17
34
 
18
35
  /** The `RadioWidget` is a widget for rendering a radio group.
19
36
  * It is typically used with a string property constrained with enum options.
20
37
  *
21
38
  * @param props - The `WidgetProps` for this component
22
39
  */
23
- export default function RadioWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>({
24
- id,
25
- htmlName,
26
- options,
27
- value,
28
- required,
29
- disabled,
30
- readonly,
31
- label,
32
- hideLabel,
33
- onChange,
34
- onBlur,
35
- onFocus,
36
- }: WidgetProps<T, S, F>) {
40
+ export default function RadioWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
41
+ props: WidgetProps<T, S, F>,
42
+ ) {
43
+ const { id, htmlName, options, value, required, disabled, readonly, label, hideLabel, onChange, onBlur, onFocus } =
44
+ props;
37
45
  const { enumOptions, enumDisabled, emptyValue } = options;
46
+ const optionValueFormat = getOptionValueFormat(options);
38
47
 
39
- const _onChange = (_: any, value: any) => onChange(enumOptionsValueForIndex<S>(value, enumOptions, emptyValue));
48
+ const _onChange = (_: any, value: any) =>
49
+ onChange(enumOptionValueDecoder<S>(value, enumOptions, optionValueFormat, emptyValue));
40
50
  const _onBlur = ({ target }: FocusEvent<HTMLInputElement>) =>
41
- onBlur(id, enumOptionsValueForIndex<S>(target && target.value, enumOptions, emptyValue));
51
+ onBlur(id, enumOptionValueDecoder<S>(target && target.value, enumOptions, optionValueFormat, emptyValue));
42
52
  const _onFocus = ({ target }: FocusEvent<HTMLInputElement>) =>
43
- onFocus(id, enumOptionsValueForIndex<S>(target && target.value, enumOptions, emptyValue));
53
+ onFocus(id, enumOptionValueDecoder<S>(target && target.value, enumOptions, optionValueFormat, emptyValue));
44
54
 
45
55
  const row = options ? options.inline : false;
46
- const selectedIndex = enumOptionsIndexForValue<S>(value, enumOptions) ?? null;
56
+ const selectValue = enumOptionSelectedValue<S>(value, enumOptions, false, optionValueFormat, '');
57
+
58
+ const { rjsfSlotProps: muiSlotProps, ...otherMuiProps } = getMuiProps<T, S, F, RadioWidgetMuiProps>(options);
47
59
 
48
60
  return (
49
61
  <>
@@ -54,9 +66,11 @@ export default function RadioWidget<T = any, S extends StrictRJSFSchema = RJSFSc
54
66
  hideLabel,
55
67
  )}
56
68
  <RadioGroup
69
+ {...otherMuiProps}
70
+ {...muiSlotProps?.radioGroup}
57
71
  id={id}
58
72
  name={htmlName || id}
59
- value={selectedIndex}
73
+ value={selectValue}
60
74
  row={row as boolean}
61
75
  onChange={_onChange}
62
76
  onBlur={_onBlur}
@@ -68,9 +82,12 @@ export default function RadioWidget<T = any, S extends StrictRJSFSchema = RJSFSc
68
82
  const itemDisabled = Array.isArray(enumDisabled) && enumDisabled.indexOf(option.value) !== -1;
69
83
  const radio = (
70
84
  <FormControlLabel
71
- control={<Radio name={htmlName || id} id={optionId(id, index)} color='primary' />}
85
+ {...muiSlotProps?.formControlLabel}
86
+ control={
87
+ <Radio {...muiSlotProps?.radio} name={htmlName || id} id={optionId(id, index)} color='primary' />
88
+ }
72
89
  label={option.label}
73
- value={String(index)}
90
+ value={enumOptionValueEncoder(option.value, index, optionValueFormat)}
74
91
  key={index}
75
92
  disabled={disabled || itemDisabled || readonly}
76
93
  />
@@ -1,15 +1,26 @@
1
1
  import { FocusEvent } from 'react';
2
2
  import FormLabel from '@mui/material/FormLabel';
3
- import Slider from '@mui/material/Slider';
3
+ import Slider, { SliderProps } from '@mui/material/Slider';
4
4
  import {
5
5
  ariaDescribedByIds,
6
6
  labelValue,
7
7
  FormContextType,
8
+ GenericObjectType,
8
9
  RJSFSchema,
9
10
  StrictRJSFSchema,
10
11
  WidgetProps,
11
12
  rangeSpec,
12
13
  } from '@rjsf/utils';
14
+ import { getMuiProps } from '../util';
15
+
16
+ /** Properties available for the `rjsfSlotProps` target of the RangeWidget. */
17
+ export interface RangeWidgetMuiProps extends GenericObjectType {
18
+ /** RJSF-specific slot props for targeting child elements of the RangeWidget. */
19
+ rjsfSlotProps?: {
20
+ /** Props applied to the MUI `Slider` component. */
21
+ slider?: SliderProps;
22
+ };
23
+ }
13
24
 
14
25
  /** The `RangeWidget` component uses the `BaseInputTemplate` changing the type to `range` and wrapping the result
15
26
  * in a div, with the value along side it.
@@ -29,6 +40,8 @@ export default function RangeWidget<T = any, S extends StrictRJSFSchema = RJSFSc
29
40
  const _onBlur = ({ target }: FocusEvent<HTMLInputElement>) => onBlur(id, target && target.value);
30
41
  const _onFocus = ({ target }: FocusEvent<HTMLInputElement>) => onFocus(id, target && target.value);
31
42
 
43
+ const { rjsfSlotProps: muiSlotProps, ...otherMuiProps } = getMuiProps<T, S, F, RangeWidgetMuiProps>(options);
44
+
32
45
  return (
33
46
  <>
34
47
  {labelValue(
@@ -43,6 +56,8 @@ export default function RangeWidget<T = any, S extends StrictRJSFSchema = RJSFSc
43
56
  onBlur={_onBlur}
44
57
  onFocus={_onFocus}
45
58
  valueLabelDisplay='auto'
59
+ {...otherMuiProps}
60
+ {...muiSlotProps?.slider}
46
61
  {...sliderProps}
47
62
  aria-describedby={ariaDescribedByIds(id)}
48
63
  />
@@ -1,74 +1,93 @@
1
1
  import { ChangeEvent, FocusEvent } from 'react';
2
2
  import MenuItem from '@mui/material/MenuItem';
3
3
  import TextField, { TextFieldProps } from '@mui/material/TextField';
4
+ import { InputLabelProps as MuiInputLabelProps } from '@mui/material/InputLabel';
5
+ import { SelectProps as MuiSelectProps } from '@mui/material/Select';
4
6
  import {
5
7
  ariaDescribedByIds,
6
- enumOptionsIndexForValue,
7
- enumOptionsValueForIndex,
8
+ enumOptionSelectedValue,
9
+ enumOptionValueDecoder,
10
+ enumOptionValueEncoder,
11
+ getOptionValueFormat,
8
12
  labelValue,
9
13
  FormContextType,
14
+ GenericObjectType,
10
15
  RJSFSchema,
11
16
  StrictRJSFSchema,
12
17
  WidgetProps,
13
18
  } from '@rjsf/utils';
19
+ import { getMuiProps } from '../util';
20
+
21
+ /** Properties available for the `rjsfSlotProps` target of the SelectWidget. */
22
+ export interface SelectWidgetMuiProps extends GenericObjectType {
23
+ /** RJSF-specific slot props for targeting child elements of the SelectWidget. */
24
+ rjsfSlotProps?: {
25
+ /** Props applied to the `InputLabel` element. */
26
+ inputLabel?: MuiInputLabelProps;
27
+ /** Props applied to the `Select` element. */
28
+ select?: MuiSelectProps;
29
+ };
30
+ }
14
31
 
15
32
  /** The `SelectWidget` is a widget for rendering dropdowns.
16
33
  * It is typically used with string properties constrained with enum options.
17
34
  *
18
35
  * @param props - The `WidgetProps` for this component
19
36
  */
20
- export default function SelectWidget<
21
- T = any,
22
- S extends StrictRJSFSchema = RJSFSchema,
23
- F extends FormContextType = any,
24
- >({
25
- schema,
26
- id,
27
- name, // remove this from textFieldProps
28
- htmlName,
29
- options,
30
- label,
31
- hideLabel,
32
- required,
33
- disabled,
34
- placeholder,
35
- readonly,
36
- value,
37
- multiple,
38
- autofocus,
39
- onChange,
40
- onBlur,
41
- onFocus,
42
- errorSchema,
43
- rawErrors = [],
44
- registry,
45
- uiSchema,
46
- hideError,
47
- ...textFieldProps
48
- }: WidgetProps<T, S, F>) {
37
+ export default function SelectWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
38
+ props: WidgetProps<T, S, F>,
39
+ ) {
40
+ const {
41
+ schema,
42
+ id,
43
+ name, // remove this from textFieldProps
44
+ htmlName,
45
+ options,
46
+ label,
47
+ hideLabel,
48
+ required,
49
+ disabled,
50
+ placeholder,
51
+ readonly,
52
+ value,
53
+ multiple,
54
+ autofocus,
55
+ onChange,
56
+ onBlur,
57
+ onFocus,
58
+ errorSchema,
59
+ rawErrors = [],
60
+ registry,
61
+ uiSchema,
62
+ hideError,
63
+ ...textFieldProps
64
+ } = props;
49
65
  const { enumOptions, enumDisabled, emptyValue: optEmptyVal } = options;
66
+ const optionValueFormat = getOptionValueFormat(options);
50
67
 
51
- multiple = typeof multiple === 'undefined' ? false : !!multiple;
68
+ const isMultiple = typeof multiple === 'undefined' ? false : !!multiple;
52
69
 
53
- const emptyValue = multiple ? [] : '';
54
- const isEmpty = typeof value === 'undefined' || (multiple && value.length < 1) || (!multiple && value === emptyValue);
70
+ const emptyValue = isMultiple ? [] : '';
71
+ const isEmpty =
72
+ typeof value === 'undefined' || (isMultiple && value.length < 1) || (!isMultiple && value === emptyValue);
55
73
 
56
74
  const _onChange = ({ target: { value } }: ChangeEvent<{ value: string }>) =>
57
- onChange(enumOptionsValueForIndex<S>(value, enumOptions, optEmptyVal));
75
+ onChange(enumOptionValueDecoder<S>(value, enumOptions, optionValueFormat, optEmptyVal));
58
76
  const _onBlur = ({ target }: FocusEvent<HTMLInputElement>) =>
59
- onBlur(id, enumOptionsValueForIndex<S>(target && target.value, enumOptions, optEmptyVal));
77
+ onBlur(id, enumOptionValueDecoder<S>(target && target.value, enumOptions, optionValueFormat, optEmptyVal));
60
78
  const _onFocus = ({ target }: FocusEvent<HTMLInputElement>) =>
61
- onFocus(id, enumOptionsValueForIndex<S>(target && target.value, enumOptions, optEmptyVal));
62
- const selectedIndexes = enumOptionsIndexForValue<S>(value, enumOptions, multiple);
79
+ onFocus(id, enumOptionValueDecoder<S>(target && target.value, enumOptions, optionValueFormat, optEmptyVal));
80
+ const { rjsfSlotProps: muiSlotProps, ...otherMuiProps } = getMuiProps<T, S, F, SelectWidgetMuiProps>(options);
81
+
63
82
  const { InputLabelProps, SelectProps, autocomplete, ...textFieldRemainingProps } = textFieldProps;
64
- const showPlaceholderOption = !multiple && schema.default === undefined;
83
+ const showPlaceholderOption = !isMultiple && schema.default === undefined;
65
84
 
66
85
  return (
67
86
  <TextField
68
87
  id={id}
69
88
  name={htmlName || id}
70
89
  label={labelValue(label || undefined, hideLabel, undefined)}
71
- value={!isEmpty && typeof selectedIndexes !== 'undefined' ? selectedIndexes : emptyValue}
90
+ value={enumOptionSelectedValue<S>(value, enumOptions, isMultiple, optionValueFormat, emptyValue)}
72
91
  required={required}
73
92
  disabled={disabled || readonly}
74
93
  autoFocus={autofocus}
@@ -78,15 +97,18 @@ export default function SelectWidget<
78
97
  onChange={_onChange}
79
98
  onBlur={_onBlur}
80
99
  onFocus={_onFocus}
81
- {...(textFieldRemainingProps as TextFieldProps)}
100
+ {...({ ...otherMuiProps, ...textFieldRemainingProps } as TextFieldProps)}
82
101
  select // Apply this and the following props after the potential overrides defined in textFieldProps
83
- InputLabelProps={{
84
- ...InputLabelProps,
85
- shrink: !isEmpty,
86
- }}
87
- SelectProps={{
88
- ...SelectProps,
89
- multiple,
102
+ slotProps={{
103
+ ...muiSlotProps,
104
+ inputLabel: {
105
+ ...muiSlotProps?.inputLabel,
106
+ shrink: !isEmpty,
107
+ },
108
+ select: {
109
+ ...muiSlotProps?.select,
110
+ multiple,
111
+ },
90
112
  }}
91
113
  aria-describedby={ariaDescribedByIds(id)}
92
114
  >
@@ -95,7 +117,7 @@ export default function SelectWidget<
95
117
  enumOptions.map(({ value, label }, i: number) => {
96
118
  const disabled: boolean = Array.isArray(enumDisabled) && enumDisabled.indexOf(value) !== -1;
97
119
  return (
98
- <MenuItem key={i} value={String(i)} disabled={disabled}>
120
+ <MenuItem key={i} value={enumOptionValueEncoder(value, i, optionValueFormat)} disabled={disabled}>
99
121
  {label}
100
122
  </MenuItem>
101
123
  );