diff --git a/packages/examples/src/examples/control-options.ts b/packages/examples/src/examples/control-options.ts index cd46d2e84..200823f7f 100644 --- a/packages/examples/src/examples/control-options.ts +++ b/packages/examples/src/examples/control-options.ts @@ -31,7 +31,8 @@ export const schema = { type: 'string' }, boolean: { - type: 'boolean' + type: 'boolean', + description: 'Boolean description as a tooltip' }, number: { type: 'number' diff --git a/packages/material-renderers/src/controls/MaterialBooleanControl.tsx b/packages/material-renderers/src/controls/MaterialBooleanControl.tsx index f2841b4d0..910bd3eaa 100644 --- a/packages/material-renderers/src/controls/MaterialBooleanControl.tsx +++ b/packages/material-renderers/src/controls/MaterialBooleanControl.tsx @@ -23,15 +23,17 @@ THE SOFTWARE. */ import isEmpty from 'lodash/isEmpty'; +import merge from 'lodash/merge'; import React from 'react'; import { isBooleanControl, RankedTester, rankWith, - ControlProps + ControlProps, + isDescriptionHidden } from '@jsonforms/core'; import { withJsonFormsControlProps } from '@jsonforms/react'; -import { FormControlLabel, Hidden } from '@mui/material'; +import { FormControlLabel, FormHelperText, Tooltip, Hidden } from '@mui/material'; import { MuiCheckbox } from '../mui-controls/MuiCheckbox'; export const MaterialBooleanControl = ({ @@ -46,30 +48,71 @@ export const MaterialBooleanControl = ({ handleChange, errors, path, - config + config, + description }: ControlProps) => { + + const isValid = errors.length === 0; + const appliedUiSchemaOptions = merge({}, config, uischema.options); + + const showDescription = !isDescriptionHidden( + visible, + description, + // Checkboxes do not receive focus until they are used, so + // we cannot rely on focus as criteria for showing descriptions. + // So we pass "false" to treat it as unfocused. + false, + appliedUiSchemaOptions.showUnfocusedDescription + ); + + const showTooltip = !showDescription && !isDescriptionHidden( + visible, + description, + // Tooltips have their own focus handlers, so we do not need to rely + // on focus state here. So we pass 'true' to treat it as focused. + true, + // We also pass true here for showUnfocusedDescription since it should + // render regardless of that setting. + true + ); + + const firstFormHelperText = showDescription + ? description + : !isValid + ? errors + : null; + const secondFormHelperText = showDescription && !isValid ? errors : null; + return ( - - } - /> + + + } + /> + + + {firstFormHelperText} + + + {secondFormHelperText} + ); }; diff --git a/packages/material-renderers/src/controls/MaterialBooleanToggleControl.tsx b/packages/material-renderers/src/controls/MaterialBooleanToggleControl.tsx index 48501d3a3..1bc6b9157 100644 --- a/packages/material-renderers/src/controls/MaterialBooleanToggleControl.tsx +++ b/packages/material-renderers/src/controls/MaterialBooleanToggleControl.tsx @@ -23,6 +23,7 @@ THE SOFTWARE. */ import isEmpty from 'lodash/isEmpty'; +import merge from 'lodash/merge'; import React from 'react'; import { isBooleanControl, @@ -30,10 +31,11 @@ import { rankWith, ControlProps, optionIs, - and + and, + isDescriptionHidden } from '@jsonforms/core'; import { withJsonFormsControlProps } from '@jsonforms/react'; -import { FormControlLabel, Hidden } from '@mui/material'; +import { FormControlLabel, FormHelperText, Tooltip, Hidden } from '@mui/material'; import { MuiToggle } from '../mui-controls/MuiToggle'; export const MaterialBooleanToggleControl = ({ @@ -48,30 +50,71 @@ export const MaterialBooleanToggleControl = ({ handleChange, errors, path, - config + config, + description }: ControlProps) => { + + const isValid = errors.length === 0; + const appliedUiSchemaOptions = merge({}, config, uischema.options); + + const showDescription = !isDescriptionHidden( + visible, + description, + // Checkboxes do not receive focus until they are used, so + // we cannot rely on focus as criteria for showing descriptions. + // So we pass "false" to treat it as unfocused. + false, + appliedUiSchemaOptions.showUnfocusedDescription + ); + + const showTooltip = !showDescription && !isDescriptionHidden( + visible, + description, + // Tooltips have their own focus handlers, so we do not need to rely + // on focus state here. So we pass 'true' to treat it as focused. + true, + // We also pass true here for showUnfocusedDescription since it should + // render regardless of that setting. + true + ); + + const firstFormHelperText = showDescription + ? description + : !isValid + ? errors + : null; + const secondFormHelperText = showDescription && !isValid ? errors : null; + return ( - - } - /> + + + } + /> + + + {firstFormHelperText} + + + {secondFormHelperText} + ); };