@mui/material#FormHelperText TypeScript Examples
The following examples show how to use
@mui/material#FormHelperText.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: FieldDescription.tsx From firecms with MIT License | 6 votes |
/**
* Render the field description for a property
* @category Form custom fields
*/
export function FieldDescription<T extends CMSType>({ property }: FieldDescriptionPopoverProps<T>) {
const disabledTooltip: string | undefined = typeof property.disabled === "object" ? property.disabled.disabledMessage : undefined;
return (
// <FormHelperText>{disabledTooltip ? disabledTooltip : property.description}</FormHelperText>
<Box display="flex">
<Box flexGrow={1}>
<FormHelperText>{disabledTooltip || property.description}</FormHelperText>
</Box>
{property.longDescription &&
<Tooltip title={
<Typography
variant={"caption"}>{property.longDescription}</Typography>
}
placement="bottom-start"
arrow>
<IconButton
edge={"start"}
size={"small"}>
<InfoIcon color={"disabled"}
fontSize={"small"}/>
</IconButton>
</Tooltip>}
</Box>
);
}
Example #2
Source File: CampaignTypeSelect.tsx From frontend with MIT License | 6 votes |
export default function CampaignTypeSelect({ name = 'campaignTypeId' }) {
const { t } = useTranslation()
const { data } = useCampaignTypesList()
const [field, meta] = useField(name)
const helperText = meta.touched ? translateError(meta.error as TranslatableField, t) : ''
return (
<FormControl
fullWidth
size="small"
variant="outlined"
error={Boolean(meta.error) && Boolean(meta.touched)}>
<InputLabel>{t('campaigns:campaign.type')}</InputLabel>
<Select fullWidth defaultValue="" label={t('campaigns:campaign.type')} {...field}>
<MenuItem value="" disabled>
{t('campaigns:campaign.type')}
</MenuItem>
{data?.map((campaignType, index) => (
<MenuItem key={index} value={campaignType.id}>
{campaignType.name}
</MenuItem>
))}
</Select>
{helperText && <FormHelperText error>{helperText}</FormHelperText>}
</FormControl>
)
}
Example #3
Source File: BeneficiarySelect.tsx From frontend with MIT License | 6 votes |
export default function BeneficiarySelect({ name = 'beneficiaryId' }) {
const { t } = useTranslation()
const { data } = useBeneficiariesList()
const [field, meta] = useField(name)
const helperText = meta.touched ? translateError(meta.error as TranslatableField, t) : ''
return (
<FormControl
fullWidth
size="small"
variant="outlined"
error={Boolean(meta.error) && Boolean(meta.touched)}>
<InputLabel>{t('Бенефициент')}</InputLabel>
<Select fullWidth defaultValue="" label={t('Бенефициент')} {...field}>
<MenuItem value="" disabled>
{t('Бенефициент')}
</MenuItem>
{data?.map((beneficiary, index) => (
<MenuItem key={index} value={beneficiary.id}>
{beneficiary.person
? `${beneficiary.person.firstName} ${beneficiary.person.lastName}`
: `${beneficiary.company?.name}`}
</MenuItem>
))}
</Select>
{helperText && <FormHelperText error>{helperText}</FormHelperText>}
</FormControl>
)
}
Example #4
Source File: AdditionalQuestions.tsx From frontend with MIT License | 6 votes |
Question = ({ question }: QuestionProps) => {
const { t } = useTranslation()
const formik = useFormikContext<SupportFormData>()
if (!question) {
return null
}
return (
<FormControl fullWidth required error={Boolean(formik.errors.roles)} component="fieldset">
<FormGroup>
<FormLabel component="legend">{t(question.title)}</FormLabel>
{question.options.map((option: Option, index) => (
<React.Fragment key={index}>
<CheckboxField label={option.label} name={option.name} />
{option.textFieldOptions && option.value ? (
<FormTextField
type="text"
name={option.textFieldOptions.name}
label={option.textFieldOptions.placeholder}
placeholder={t(option.textFieldOptions.placeholder)}
/>
) : null}
</React.Fragment>
))}
</FormGroup>
{Boolean(formik.errors[question.key]) && (
<FormHelperText error>{t(question.errorMessage)}</FormHelperText>
)}
</FormControl>
)
}
Example #5
Source File: SelectCountry.tsx From frontend with MIT License | 6 votes |
export default function SelectCountry({ name = 'countryId' }) {
const { t } = useTranslation()
const { data } = useCountriesList()
const [field, meta] = useField(name)
const helperText = meta.touched ? translateError(meta.error as TranslatableField, t) : ''
return (
<FormControl
fullWidth
size="small"
variant="outlined"
error={Boolean(meta.error) && Boolean(meta.touched)}>
<InputLabel>Държава</InputLabel>
<Select fullWidth defaultValue="" label="Държава" {...field}>
<MenuItem value="" disabled>
Избери държава
</MenuItem>
{data?.map((country) => (
<MenuItem key={country.id} value={country.id}>
{country.name}
</MenuItem>
))}
</Select>
{helperText && <FormHelperText error>{helperText}</FormHelperText>}
</FormControl>
)
}
Example #6
Source File: CoordinatorSelect.tsx From frontend with MIT License | 6 votes |
export default function CoordinatorSelect({ name = 'coordinatorId' }) {
const { t } = useTranslation()
const { data } = useCoordinatorsList()
const [field, meta] = useField(name)
const helperText = meta.touched ? translateError(meta.error as TranslatableField, t) : ''
return (
<FormControl
fullWidth
size="small"
variant="outlined"
error={Boolean(meta.error) && Boolean(meta.touched)}>
<InputLabel>{t('Кординатор')}</InputLabel>
<Select fullWidth defaultValue="" label={t('Кординатор')} {...field}>
<MenuItem value="" disabled>
{t('Кординатор')}
</MenuItem>
{data?.map((coordinator, index) => (
<MenuItem key={index} value={coordinator.id}>
{coordinator.person.firstName} {coordinator.person.lastName}
</MenuItem>
))}
</Select>
{helperText && <FormHelperText error>{helperText}</FormHelperText>}
</FormControl>
)
}
Example #7
Source File: CheckboxField.tsx From frontend with MIT License | 6 votes |
export default function CheckboxField({ name, label }: CheckboxFieldProps) {
const { t } = useTranslation()
const [field, meta] = useField(name)
const helperText = meta.touched ? translateError(meta.error as TranslatableField, t) : ''
return (
<FormControl required component="fieldset" error={Boolean(meta.error) && Boolean(meta.touched)}>
<FormControlLabel
label={typeof label === 'string' ? `${t(label)}` : label}
control={<Checkbox color="primary" checked={Boolean(field.value)} {...field} />}
/>
{Boolean(meta.error) && <FormHelperText error>{helperText}</FormHelperText>}
</FormControl>
)
}
Example #8
Source File: ReadOnlyField.tsx From firecms with MIT License | 5 votes |
/**
*
* Simply render the non-editable preview of a field
*
* This is one of the internal components that get mapped natively inside forms
* and tables to the specified properties.
* @category Form fields
*/
export function ReadOnlyField({
name,
value,
setValue,
error,
showError,
isSubmitting,
touched,
tableMode,
property,
includeDescription,
context
}: FieldProps<any>) {
return (
<FormControl fullWidth error={showError}>
{!tableMode && <FormHelperText filled
required={property.validation?.required}>
<LabelWithIcon property={property}/>
</FormHelperText>}
<Paper
sx={(theme) => ({
minHeight: "64px",
elevation: 0,
padding: theme.spacing(2),
[theme.breakpoints.up("md")]: {
padding: theme.spacing(3)
}
})}
variant={"outlined"}>
<ErrorBoundary>
<PreviewComponent name={name}
value={value}
property={property}
size={"regular"}/>
</ErrorBoundary>
</Paper>
{showError &&
typeof error === "string" &&
<FormHelperText>{error}</FormHelperText>}
{includeDescription &&
<FieldDescription property={property}/>}
</FormControl>
);
}
Example #9
Source File: CheckboxElement.tsx From react-hook-form-mui with MIT License | 5 votes |
export default function CheckboxElement({
name,
validation = {},
required,
parseError,
label,
control,
...rest
}: CheckboxElementProps): JSX.Element {
if (required) {
validation.required = 'This field is required'
}
return (
<Controller
name={name}
rules={validation}
control={control}
render={({ field: { value, onChange }, fieldState: { invalid, error } }) => {
const helperText = error ? (typeof parseError === 'function' ? parseError(error) : error.message) : rest.helperText
return (
<FormControl required={required} error={invalid}>
<FormGroup row>
<FormControlLabel
label={label || ''}
control={
<Checkbox
color={'primary'}
sx={{
color: invalid ? "error.main" : undefined,
}}
value={value}
checked={!!value}
onChange={() => {
onChange(!value)
//setValue(name, !formValue, { shouldValidate: true })
}}
/>
}
/>
</FormGroup>
{helperText && <FormHelperText error={invalid}>{helperText}</FormHelperText>}
</FormControl>
)
}}
/>
)
}
Example #10
Source File: SwitchField.tsx From firecms with MIT License | 5 votes |
SwitchFieldComponent = React.forwardRef(function({
name,
value,
setValue,
error,
showError,
autoFocus,
disabled,
touched,
property,
includeDescription,
shouldAlwaysRerender
}: SwitchFieldProps, ref) {
const classes = useStyles();
useClearRestoreValue({
property,
value,
setValue
});
const [focus, setFocus] = useState<boolean>(autoFocus);
return (
<>
<FormControl fullWidth>
<FormControlLabel
className={clsx(classes.formControl,
{
[classes.focus]: focus
})}
onClick={(e) => setFocus(true)}
labelPlacement={"start"}
checked={Boolean(value)}
inputRef={ref}
control={
<Switch
type={"checkbox"}
color={"secondary"}
autoFocus={autoFocus}
disabled={disabled}
onFocus={(e) => setFocus(true)}
onBlur={(e) => setFocus(false)}
onChange={(evt) => {
setFocus(true);
setValue(
evt.target.checked
);
}}/>
}
disabled={disabled}
label={
<Typography color={"textSecondary"}>
<LabelWithIcon
property={property}/>
</Typography>}
/>
{includeDescription &&
<FieldDescription property={property}/>}
{showError && <FormHelperText>{error}</FormHelperText>}
</FormControl>
</>
);
})
Example #11
Source File: CircleCheckboxField.tsx From frontend with MIT License | 5 votes |
export default function CircleCheckboxField({ name, label, labelProps }: CircleCheckboxField) {
const { t } = useTranslation('one-time-donation')
const [field, meta] = useField(name)
const helperText = meta.touched ? translateError(meta.error as TranslatableField, t) : ''
return (
<FormControl required component="fieldset" error={Boolean(meta.error) && Boolean(meta.touched)}>
<FormControlLabel
sx={
field.checked
? {
background: lighten(theme.palette.primary.main, 0.8),
border: `1px solid ${theme.borders.light}`,
}
: undefined
}
label={<Typography sx={{ fontWeight: 'bold', ml: 1 }}>{label}</Typography>}
control={
<Checkbox
icon={
<Icon
sx={(theme) => ({
width: 30,
height: 30,
border: `1px solid ${theme.palette.primary.dark}`,
// @ts-expect-error theme doesn't include overrides
borderRadius: theme.borders.round,
})}
/>
}
checkedIcon={
<CheckIcon
sx={(theme) => ({
width: 30,
height: 30,
border: `1px solid ${theme.palette.primary.main}`,
backgroundColor: theme.palette.primary.main,
// @ts-expect-error theme doesn't include overrides
borderRadius: theme.borders.round,
color: '#fff',
})}
/>
}
checked={Boolean(field.value)}
{...field}
/>
}
{...labelProps}
/>
{Boolean(meta.error) && (
<FormHelperText error>{helperText ? t(helperText) : 'General Error'}</FormHelperText>
)}
</FormControl>
)
}
Example #12
Source File: MarkdownField.tsx From firecms with MIT License | 5 votes |
/**
* Render a markdown field that allows edition and seeing the preview.
*
* This is one of the internal components that get mapped natively inside forms
* and tables to the specified properties.
* @category Form fields
*/
export function MarkdownField({
name,
value,
setValue,
error,
showError,
disabled,
autoFocus,
touched,
property,
tableMode,
includeDescription,
context,
shouldAlwaysRerender
}: MarkDownFieldProps) {
const classes = useStyles();
useClearRestoreValue({
property,
value,
setValue
});
const updateValue = (newValue: string | undefined) => {
if (!newValue) {
setValue(
null
);
} else {
setValue(
newValue
);
}
};
return (
<FormControl
required={property.validation?.required}
error={showError}
fullWidth>
{!tableMode && <FormHelperText filled
required={property.validation?.required}>
<LabelWithIcon property={property}/>
</FormHelperText>}
<div className={classes.root}>
<MDEditor
value={typeof value === "string" ? value : ""}
preview={"edit"}
onChange={(value) => updateValue(value)}
/>
</div>
<Box display={"flex"}>
<Box flexGrow={1}>
{showError &&
typeof error === "string" &&
<FormHelperText>{error}</FormHelperText>}
{includeDescription &&
<FieldDescription property={property}/>}
</Box>
</Box>
</FormControl>
);
}
Example #13
Source File: RadioButtonGroup.tsx From frontend with MIT License | 5 votes |
export default function RadioButtonGroup({
name,
options,
muiRadioGroupProps,
muiRadioButtonGridProps,
}: RadioButtonGroup) {
const { t } = useTranslation('one-time-donation')
const [field, meta, { setValue }] = useField(name)
const helperText = meta.touched ? translateError(meta.error as TranslatableField, t) : ''
return (
<FormControl
fullWidth
required
component="fieldset"
error={Boolean(meta.error) && Boolean(meta.touched)}>
<RadioGroup
onChange={(e, v) => {
setValue(v)
}}
value={field.value}
name={name}
{...muiRadioGroupProps}>
<Grid rowSpacing={2} columnSpacing={2} container>
{options ? (
<>
{options.map(({ label: optionLabel, value: optionValue }, index) => (
<Grid key={index} item xs={12} sm={6} {...muiRadioButtonGridProps}>
<PriceRadioButton
value={optionValue}
checked={optionValue == field.value}
label={optionLabel}
/>
</Grid>
))}
</>
) : (
<Typography>There are no avaliable choices you can make :(</Typography>
)}
</Grid>
</RadioGroup>
{Boolean(meta.error) && Boolean(meta.touched) && helperText && (
<FormHelperText error>{t(helperText)}</FormHelperText>
)}
</FormControl>
)
}
Example #14
Source File: Roles.tsx From frontend with MIT License | 5 votes |
export default function Roles() {
const [, { error }] = useField('roles')
const { t } = useTranslation()
return (
<Grid container spacing={6} justifyContent="center">
<Grid item xs={12} md={8}>
<HeaderTypography>{t('support:steps.role.subtitle')}</HeaderTypography>
</Grid>
<Grid item xs={12} md={8}>
<Typography variant="h5" paragraph>
{t('support:steps.role.first-subtitle')}
</Typography>
<Divider />
<div>
<BankTransfer />
</div>
</Grid>
<Grid item xs={12} md={8}>
<Typography variant="h5" paragraph>
{t('support:steps.role.second-subtitle')}
</Typography>
<Divider />
<FormControl fullWidth required error={!!error} component="fieldset">
<FormGroup>
<Role name="roles.benefactor" label={t('support:steps.role.fields.benefactor.title')} />
<Role label={t('support:steps.role.fields.volunteer.title')} name="roles.volunteer" />
<Role
label={t('support:steps.role.fields.associationMember.title')}
name="roles.associationMember"
/>
<Role label={t('support:steps.role.fields.partner.title')} name="roles.partner" />
<Role label={t('support:steps.role.fields.company.title')} name="roles.company" />
</FormGroup>
{error && <FormHelperText>{t('validation:select-role')}</FormHelperText>}
</FormControl>
</Grid>
</Grid>
)
}
Example #15
Source File: SubPropertyField.tsx From firecms with MIT License | 5 votes |
CustomField = ({
property,
value,
name,
tableMode,
error,
showError,
includeDescription,
context,
setValue,
}: FieldProps<object>) => {
useEffect(() => {
if (!value) setValue({});
}, [value, setValue]);
return (
<FormControl fullWidth error={showError}>
{!tableMode && (
<FormHelperText filled required={property.validation?.required}>
<LabelWithIcon property={property} />
</FormHelperText>
)}
<Paper elevation={0}>
{buildPropertyField({
name: `${name}.sample`,
property: {
title: "Sample",
dataType: "string",
validation: {
required: true,
},
},
context,
})}
</Paper>
{includeDescription && <FieldDescription property={property} />}
{showError && typeof error === "string" && (
<FormHelperText>{error}</FormHelperText>
)}
</FormControl>
);
}
Example #16
Source File: CustomShapedArrayField.tsx From firecms with MIT License | 5 votes |
export default function CustomShapedArrayField({
property,
name,
value,
setValue,
customProps,
touched,
error,
isSubmitting,
showError,
includeDescription,
context,
...props
}: FieldProps<any[], CustomShapedArrayProps>)
: ReactElement {
const properties = customProps.properties;
return (
<FormControl fullWidth error={showError}>
<FormHelperText>{property.title ?? name}</FormHelperText>
<Paper variant={"outlined"}>
<Box m={2}>
{properties.map((property, index) =>
<div key={`array_${index}`}>
{buildPropertyField({
name: `${name}[${index}]`,
property,
context
})}
</div>
)}
</Box>
</Paper>
{includeDescription &&
<FieldDescription property={property}/>}
{showError
&& typeof error === "string"
&& <FormHelperText>{error}</FormHelperText>}
</FormControl>
);
}
Example #17
Source File: select.tsx From Search-Next with GNU General Public License v3.0 | 4 votes |
Select: React.FC<SelectProps> = ({
label,
size = 'small',
options,
optionsConfig,
helperText,
error,
inputRef,
...props
}) => {
const theme = createTheme();
return (
<Box sx={{ minWidth: 120 }}>
<FormControl fullWidth>
<InputLabel
id={`mui-select-label-${label}`}
className={css`
&.MuiFormLabel-root {
transform: translate(14px, 9px) scale(1);
}
&.Mui-focused,
&.MuiFormLabel-filled {
transform: translate(14px, -9px) scale(0.75);
}
`}
>
{label}
</InputLabel>
<StyledSelect
{...props}
labelId={`mui-select-label-${label}`}
id={`mui-select-${label}`}
inputRef={inputRef}
label={label}
size={size}
error={error}
onClose={(e) => e.stopPropagation()}
MenuProps={{
sx: {
'& .MuiPaper-root': {
backgroundColor: 'rgba(253, 253, 253, 0.8)',
backdropFilter: 'blur(8px)',
borderRadius: '4px',
marginTop: theme.spacing(1),
minWidth: 140,
color:
theme.palette.mode === 'light'
? 'rgb(55, 65, 81)'
: theme.palette.grey[300],
boxShadow:
'rgb(255, 255, 255) 0px 0px 0px 0px, rgba(0, 0, 0, 0.05) 0px 0px 0px 1px, rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px',
'& .MuiMenu-list': {
padding: '0 4px',
},
'& .MuiMenuItem-root': {
borderRadius: '4px',
padding: '4px 8px',
margin: '4px 0',
fontSize: '14px',
transition: 'all 0.3s',
'& .MuiSvgIcon-root': {
fontSize: '14px',
},
'&:active': {
backgroundColor: alpha(
theme.palette.primary.main,
theme.palette.action.selectedOpacity,
),
},
},
},
},
}}
>
{options.map((i) => {
const label =
optionsConfig && optionsConfig.label
? i[optionsConfig.label]
: i.label;
const value =
optionsConfig && optionsConfig.value
? i[optionsConfig.value]
: i.value;
return (
<MenuItem key={value} value={value}>
{label}
</MenuItem>
);
})}
</StyledSelect>
<FormHelperText error={error}>{helperText}</FormHelperText>
</FormControl>
</Box>
);
}
Example #18
Source File: RadioButtonGroup.tsx From react-hook-form-mui with MIT License | 4 votes |
export default function RadioButtonGroup({
helperText,
options,
label,
name,
parseError,
labelKey = 'label',
valueKey = 'id',
required,
emptyOptionLabel,
returnObject,
row,
control,
...rest
}: RadioButtonGroupProps): JSX.Element {
const theme = useTheme()
const { field: { value, onChange }, fieldState: { invalid, error } } = useController({
name,
rules: required ? { required: 'This field is required' } : undefined,
control
})
helperText = error ? (typeof parseError === 'function' ? parseError(error) : error.message) : helperText
const onRadioChange = (event: ChangeEvent<HTMLInputElement>) => {
const radioValue = (event.target as HTMLInputElement).value
const returnValue = returnObject
? options.find(items => items[valueKey] === radioValue)
: radioValue
// setValue(name, returnValue, { shouldValidate: true })
onChange(returnValue)
if (typeof rest.onChange === 'function') {
rest.onChange(returnValue)
}
}
return (
<FormControl error={invalid}>
{label && <FormLabel required={required} error={invalid}>{label}</FormLabel>}
<RadioGroup onChange={onRadioChange}
name={name}
row={row}
value={value || ''}>
{emptyOptionLabel && (
<FormControlLabel
control={<Radio sx={{
color: invalid ? theme.palette.error.main : undefined
}} checked={!value} />}
label={emptyOptionLabel}
value=""
/>
)}
{options.map((option: any) => {
const optionKey = option[valueKey]
if (!optionKey) {
console.error(
`CheckboxButtonGroup: valueKey ${valueKey} does not exist on option`,
option
)
}
const isChecked = !!(
value &&
(returnObject
? value[valueKey] === optionKey
: value === optionKey)
)
return (
<FormControlLabel
control={<Radio sx={{
color: invalid ? theme.palette.error.main : undefined
}} checked={isChecked} />}
value={optionKey}
label={option[labelKey]}
key={optionKey}
/>
)
})}
</RadioGroup>
{helperText && <FormHelperText>{helperText}</FormHelperText>}
</FormControl>
)
}
Example #19
Source File: MultiSelectElement.tsx From react-hook-form-mui with MIT License | 4 votes |
export default function MultiSelectElement({
menuItems,
label = '',
itemKey = '',
itemValue = '',
itemLabel = '',
required = false,
validation = {},
parseError,
name,
menuMaxHeight = ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
menuMaxWidth = 250,
minWidth = 120,
helperText,
showChips,
variant,
control,
showCheckbox,
...rest
}: MultiSelectElementProps): JSX.Element {
if (required) {
validation.required = 'This field is required'
}
return (
<Controller
name={name}
rules={validation}
control={control}
render={({ field: { value, onChange, onBlur }, fieldState: { invalid, error } }) => {
helperText = error ? (typeof parseError === 'function' ? parseError(error) : error.message) : helperText
return (
<FormControl
variant={variant}
style={{ minWidth }}
fullWidth={rest.fullWidth}
error={invalid}
>
{label && (
<InputLabel error={invalid} htmlFor={rest.id || `select-multi-select-${name}`} required={required}>
{label}
</InputLabel>
)}
<Select
{...rest}
id={rest.id || `select-multi-select-${name}`}
multiple
label={label || undefined}
error={invalid}
value={value || []}
required={required}
onChange={onChange}
onBlur={onBlur}
MenuProps={{
PaperProps: {
style: {
maxHeight: menuMaxHeight,
width: menuMaxWidth
}
}
}}
renderValue={typeof rest.renderValue === 'function' ? rest.renderValue : showChips ? (selected) => (
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
{(selected as any[] || []).map((selectedValue) => (
<Chip
key={selectedValue}
label={selectedValue}
style={{ display: 'flex', flexWrap: 'wrap' }}
onDelete={() => {
onChange(value.filter((i: any) => i !== selectedValue))
// setValue(name, formValue.filter((i: any) => i !== value), { shouldValidate: true })
}}
deleteIcon={<CloseIcon
onMouseDown={(ev) => {
ev.stopPropagation()
}} />
}
/>
))}
</div>
) : (selected) => selected?.join(', ')}
>
{menuItems.map((item: any) => {
const isChecked = value?.includes(item) ?? false
const key = itemValue || itemKey
let val = key ? item[key] : item
return (
<MenuItem
key={val}
value={val}
sx={{
fontWeight: (theme) => isChecked ? theme.typography.fontWeightBold : theme.typography.fontWeightRegular
}}
>
{showCheckbox && <Checkbox checked={isChecked} />}
<ListItemText primary={itemLabel ? item[itemLabel] : item} />
</MenuItem>
)
})}
</Select>
{helperText && <FormHelperText>{helperText}</FormHelperText>}
</FormControl>
)
}}
/>
)
}
Example #20
Source File: CheckboxButtonGroup.tsx From react-hook-form-mui with MIT License | 4 votes |
export default function CheckboxButtonGroup({
helperText,
options,
label,
name,
parseError,
required,
labelKey = 'label',
valueKey = 'id',
returnObject,
disabled,
row,
control,
checkboxColor,
...rest
}: CheckboxButtonGroupProps): JSX.Element {
const theme = useTheme()
const { field: { value = [], onChange }, fieldState: { invalid, error } } = useController({
name,
rules: required ? { required: 'This field is required' } : undefined,
control
})
helperText = error ? (typeof parseError === 'function' ? parseError(error) : error.message) : helperText
const handleChange = (index: number | string) => {
const newArray = [...value]
const exists =
value.findIndex((i: any) =>
returnObject ? i[valueKey] === index : i === index
) === -1
if (exists) {
newArray.push(
returnObject ? options.find(i => i[valueKey] === index) : index
)
} else {
newArray.splice(
value.findIndex((i: any) =>
returnObject ? i[valueKey] === index : i === index
),
1
)
}
// setValue(name, newArray, { shouldValidate: true })
onChange(newArray)
if (typeof rest.onChange === 'function') {
rest.onChange(newArray)
}
}
return (
<FormControl error={invalid} required={required}>
{label && <FormLabel error={invalid}>{label}</FormLabel>}
<FormGroup row={row}>
{options.map((option: any) => {
const optionKey = option[valueKey]
if (!optionKey) {
console.error(
`CheckboxButtonGroup: valueKey ${valueKey} does not exist on option`,
option
)
}
const isChecked =
value.findIndex((item: any) =>
returnObject ? item[valueKey] === optionKey : item === optionKey
) !== -1
return (
<FormControlLabel
control={
<Checkbox
sx={{
color: invalid ? theme.palette.error.main : undefined
}}
color={checkboxColor || 'primary'}
value={optionKey}
checked={isChecked}
disabled={disabled}
onChange={() => handleChange(optionKey)}
/>
}
label={option[labelKey]}
key={optionKey}
/>
)
})}
</FormGroup>
{helperText && <FormHelperText>{helperText}</FormHelperText>}
</FormControl>
)
}
Example #21
Source File: form_factory.tsx From firecms with MIT License | 4 votes |
function FieldInternal<T extends CMSType, M extends { [Key: string]: any }>
({
component,
componentProps: {
name,
property,
includeDescription,
underlyingValueHasChanged,
tableMode,
partOfArray,
autoFocus,
context,
disabled,
shouldAlwaysRerender
},
fieldProps
}:
{
component: ComponentType<FieldProps<T>>,
componentProps: CMSFormFieldProps<M>,
fieldProps: FormikFieldProps<T>
}) {
const customFieldProps: any = property.config?.customProps;
const value = fieldProps.field.value;
const initialValue = fieldProps.meta.initialValue;
const error = getIn(fieldProps.form.errors, name);
const touched = getIn(fieldProps.form.touched, name);
const showError: boolean = error &&
(fieldProps.form.submitCount > 0 || property.validation?.unique) &&
(!Array.isArray(error) || !!error.filter((e: any) => !!e).length);
const isSubmitting = fieldProps.form.isSubmitting;
const [internalValue, setInternalValue] = useState<T | null>(value);
useEffect(
() => {
const handler = setTimeout(() => {
fieldProps.form.setFieldValue(name, internalValue);
}, 50);
return () => {
clearTimeout(handler);
};
},
[internalValue]
);
useEffect(
() => {
if (!isEqual(value, internalValue)) {
setInternalValue(value);
}
},
[value]
);
const cmsFieldProps: FieldProps<T> = {
name,
value: internalValue as T,
initialValue,
setValue: (value: T | null) => {
fieldProps.form.setFieldTouched(name, true, false);
setInternalValue(value);
},
error,
touched,
showError,
isSubmitting,
includeDescription: includeDescription ?? true,
property: property as Property<T>,
disabled: disabled ?? false,
underlyingValueHasChanged: underlyingValueHasChanged ?? false,
tableMode: tableMode ?? false,
partOfArray: partOfArray ?? false,
autoFocus: autoFocus ?? false,
customProps: customFieldProps,
context,
shouldAlwaysRerender: shouldAlwaysRerender ?? true
};
return (
<>
{React.createElement(component, cmsFieldProps)}
{underlyingValueHasChanged && !isSubmitting &&
<FormHelperText>
This value has been updated elsewhere
</FormHelperText>}
</>);
}
Example #22
Source File: TextField.tsx From firecms with MIT License | 4 votes |
/**
* Generic text field.
* This is one of the internal components that get mapped natively inside forms
* and tables to the specified properties.
* @category Form fields
*/
export function TextField<T extends string | number>({
name,
value,
setValue,
error,
showError,
disabled,
autoFocus,
property,
includeDescription,
allowInfinity,
shouldAlwaysRerender
}: TextFieldProps<T>) {
const classes = formStyles();
let mediaType: MediaType | undefined;
let multiline: boolean | undefined;
if (property.dataType === "string") {
const url = (property as StringProperty).config?.url;
mediaType = typeof url === "string" ? url : undefined;
multiline = (property as StringProperty).config?.multiline;
}
useClearRestoreValue({
property,
value,
setValue
});
const isMultiline = !!multiline;
const internalValue = value ?? (property.dataType === "string" ? "" : value === 0 ? 0 : "");
const valueIsInfinity = internalValue === Infinity;
const inputType = !valueIsInfinity && property.dataType === "number" ? "number" : undefined;
const updateValue = (newValue: typeof internalValue | undefined) => {
if (!newValue) {
setValue(
null
);
} else if (inputType === "number") {
const numValue = parseFloat(newValue as string);
setValue(
numValue as T
);
} else {
setValue(
newValue
);
}
};
const filledInput = (
<FilledInput
sx={{
minHeight: "64px"
}}
autoFocus={autoFocus}
type={inputType}
multiline={isMultiline}
inputProps={{
rows: 4
}}
value={valueIsInfinity ? "Infinity" : (value ?? "")}
disabled={disabled}
onChange={(evt) => {
updateValue(evt.target.value as T);
}}
/>
);
return (
<>
<FormControl
variant="filled"
required={property.validation?.required}
error={showError}
disabled={valueIsInfinity}
fullWidth>
<InputLabel
classes={{
root: classes.inputLabel,
shrink: classes.shrinkInputLabel
}}>
<LabelWithIcon property={property}/>
</InputLabel>
{filledInput}
<Box display={"flex"}>
<Box flexGrow={1}>
{showError && <FormHelperText>{error}</FormHelperText>}
{includeDescription &&
<FieldDescription property={property}/>}
</Box>
{allowInfinity &&
<FormControlLabel
checked={valueIsInfinity}
style={{ marginRight: 0 }}
labelPlacement={"start"}
control={
<Switch
size={"small"}
type={"checkbox"}
onChange={(evt) => {
updateValue(
evt.target.checked ? Infinity as T : undefined);
}}/>
}
disabled={disabled}
label={
<Typography variant={"caption"}>
Set value to Infinity
</Typography>
}
/>
}
</Box>
</FormControl>
{mediaType && internalValue &&
<ErrorBoundary>
<Box m={1}>
<PreviewComponent name={name}
value={internalValue}
property={property}
size={"regular"}/>
</Box>
</ErrorBoundary>
}
</>
);
}
Example #23
Source File: StorageUploadField.tsx From firecms with MIT License | 4 votes |
/**
* Field that allows to upload files to Google Cloud Storage.
*
* This is one of the internal components that get mapped natively inside forms
* and tables to the specified properties.
* @category Form fields
*/
export function StorageUploadField({
name,
value,
setValue,
error,
showError,
autoFocus,
tableMode,
property,
includeDescription,
context,
isSubmitting
}: StorageUploadFieldProps) {
const multipleFilesSupported = property.dataType === "array";
const disabled = isReadOnly(property) || !!property.disabled || isSubmitting;
const internalValue = multipleFilesSupported
? (Array.isArray(value) ? value : [])
: value;
useClearRestoreValue<string | string[]>({
property,
value,
setValue
});
const storageMeta: StorageMeta | undefined = property.dataType === "string"
? property.config?.storageMeta
: property.dataType === "array" &&
(property.of as Property).dataType === "string"
? (property.of as StringProperty).config?.storageMeta
: undefined;
if (!storageMeta)
throw Error("Storage meta must be specified");
const fileNameBuilder = (file: File) => {
if (storageMeta.fileName) {
const fileName = storageMeta.fileName({
entityId: context.entityId,
values: context.values,
property,
file,
storageMeta,
name
});
if (!fileName || fileName.length === 0) {
throw Error("You need to return a valid filename");
}
return fileName;
}
return file.name;
};
const storagePathBuilder = (file: File) => {
if (typeof storageMeta.storagePath === "string")
return storageMeta.storagePath;
if (typeof storageMeta.storagePath === "function") {
const storagePath = storageMeta.storagePath({
entityId: context.entityId,
values: context.values,
property,
file,
storageMeta,
name
});
if (!storagePath || storagePath.length === 0) {
throw Error("You need to return a valid filename");
}
return storagePath;
}
console.warn("When using a storage property, if you don't specify the storagePath, the root storage is used");
return "/";
};
return (
<FormControl fullWidth
required={property.validation?.required}
error={showError}>
{!tableMode &&
<FormHelperText filled
required={property.validation?.required}>
<LabelWithIcon property={property}/>
</FormHelperText>}
<StorageUpload
value={internalValue}
name={name}
disabled={disabled}
autoFocus={autoFocus}
property={property}
onChange={(newValue) => {
setValue(newValue);
}}
fileNameBuilder={fileNameBuilder}
storagePathBuilder={storagePathBuilder}
storageMeta={storageMeta}
multipleFilesSupported={multipleFilesSupported}/>
{includeDescription &&
<FieldDescription property={property as any}/>}
{showError && <FormHelperText>{error}</FormHelperText>}
</FormControl>
);
}
Example #24
Source File: Select.tsx From firecms with MIT License | 4 votes |
/**
* If `enumValues` are set in the string config, this field renders a select
* where each option is a colored chip.
*
* This is one of the internal components that get mapped natively inside forms
* and tables to the specified properties.
* @category Form fields
*/
export function Select<T extends EnumType>({
name,
value,
setValue,
error,
showError,
disabled,
autoFocus,
touched,
property,
includeDescription,
shouldAlwaysRerender
}: SelectProps<T>) {
const classes = formStyles();
const enumValues = property.config?.enumValues as EnumValues;
useClearRestoreValue({
property,
value,
setValue
});
return (
<FormControl
variant="filled"
fullWidth
required={property.validation?.required}
error={showError}
disabled={disabled}
>
<InputLabel id={`${name}-select-label`}
classes={{
root: classes.inputLabel,
shrink: classes.shrinkInputLabel
}}>
<LabelWithIcon property={property}/>
</InputLabel>
<MuiSelect
sx={{
minHeight: "64px"
}}
variant={"filled"}
labelId={`${name}-select-label`}
autoFocus={autoFocus}
value={value !== undefined ? value : ""}
disabled={disabled}
onChange={(evt: any) => {
const eventValue = evt.target.value;
const newValue = eventValue
? (property.dataType === "number" ? parseFloat(eventValue) : eventValue)
: null;
return setValue(newValue);
}}
renderValue={(enumKey: any) => {
return <EnumValuesChip
enumKey={enumKey}
enumValues={enumValues}
small={false}/>;
}
}>
{enumToObjectEntries(enumValues)
.map(([enumKey, labelOrConfig]) => {
return (
<MenuItem key={`select_${name}_${enumKey}`}
value={enumKey}
disabled={isEnumValueDisabled(labelOrConfig)}>
<EnumValuesChip
enumKey={enumKey}
enumValues={enumValues}
small={true}/>
</MenuItem>
);
})}
</MuiSelect>
{includeDescription &&
<FieldDescription property={property}/>}
{showError && <FormHelperText>{error}</FormHelperText>}
</FormControl>
);
}
Example #25
Source File: ReferenceField.tsx From firecms with MIT License | 4 votes |
/**
* Field that opens a reference selection dialog.
*
* This is one of the internal components that get mapped natively inside forms
* and tables to the specified properties.
* @category Form fields
*/
export function ReferenceField<M extends { [Key: string]: any }>({
name,
value,
setValue,
error,
showError,
disabled,
touched,
autoFocus,
property,
includeDescription,
context,
shouldAlwaysRerender
}: FieldProps<EntityReference>) {
if (typeof property.path !== "string") {
throw Error("Picked the wrong component ReferenceField");
}
useClearRestoreValue({
property,
value,
setValue
});
const classes = useStyles();
const [open, setOpen] = React.useState(autoFocus);
const sideEntityController = useSideEntityController();
const navigationContext = useNavigation();
const collectionResolver: EntityCollectionResolver | undefined = useMemo(() => {
return navigationContext.getCollectionResolver(property.path as string);
}, [property.path, navigationContext]);
if (!collectionResolver) {
throw Error(`Couldn't find the corresponding collection for the path: ${property.path}`);
}
const schemaResolver = collectionResolver.schemaResolver;
const path = property.path;
const validValue = value && value instanceof EntityReference;
const {
entity,
dataLoading,
dataLoadingError
} = useEntityFetch({
path: validValue ? value.path : undefined,
entityId: validValue ? value.id : undefined,
schema: schemaResolver,
useCache: true
});
const handleEntityClick = (entity: Entity<M>) => {
if (disabled)
return;
setValue(entity ? getReferenceFrom(entity) : null);
setOpen(false);
};
const handleClickOpen = () => {
setOpen(true);
};
const clearValue = (e: React.MouseEvent) => {
e.stopPropagation();
setValue(null);
setOpen(false);
};
const seeEntityDetails = (e: React.MouseEvent) => {
e.stopPropagation();
if (entity)
sideEntityController.open({
entityId: entity.id,
path,
overrideSchemaRegistry: false
});
};
const onClose = () => {
setOpen(false);
};
function buildEntityView(schemaResolver?: EntitySchemaResolver) {
const missingEntity = entity && !entity.values;
let body: JSX.Element;
if (!schemaResolver) {
body = (
<ErrorView
error={"The specified collection does not exist. Check console"}/>
);
} else if (missingEntity) {
body = (
<Tooltip title={value && value.path}>
<Box
display={"flex"}
alignItems={"center"}
p={1}
flexGrow={1}>
<ErrorIcon fontSize={"small"} color={"error"}/>
<Box marginLeft={1}>Missing
reference {entity && entity.id}</Box>
</Box>
</Tooltip>
);
} else {
if (validValue) {
const schema = schemaResolver({});
const allProperties = Object.keys(schema.properties);
let listProperties = property.previewProperties?.filter(p => allProperties.includes(p as string));
if (!listProperties || !listProperties.length) {
listProperties = allProperties;
}
listProperties = listProperties.slice(0, 3);
body = (
<Box display={"flex"}
flexDirection={"column"}
flexGrow={1}
ml={1}
mr={1}>
{listProperties && listProperties.map((key, index) => {
const property = schema.properties[key as string];
if (!property) return null;
return (
<Box
key={`reference_previews_${key as string}`}
mt={0.5}
mb={0.5}>
<ErrorBoundary>{
entity
? <PreviewComponent
name={key as string}
value={(entity.values as any)[key]}
property={property as AnyProperty}
size={"tiny"}/>
: <SkeletonComponent
property={property as AnyProperty}
size={"tiny"}/>}
</ErrorBoundary>
</Box>
);
})}
</Box>
);
} else {
body = <Box p={1}
onClick={disabled ? undefined : handleClickOpen}
justifyContent="center"
display="flex">
<Typography variant={"body2"} sx={(theme) => ({
flexGrow: 1,
textAlign: "center",
color: "#838383",
fontWeight: theme.typography.fontWeightMedium
})}>No value set</Typography>
{!disabled && <Button variant="outlined"
color="primary">
Set
</Button>}
</Box>;
}
}
return (
<Box
onClick={disabled ? undefined : handleClickOpen}
display="flex">
<Box display={"flex"}
flexDirection={"column"}
flexGrow={1}>
<Box display={"flex"}
flexDirection={"row"}
flexGrow={1}>
<Box flexGrow={1}>
<FormHelperText filled
required={property.validation?.required}>
<LabelWithIcon
property={property}/>
</FormHelperText>
</Box>
{entity &&
<Box
alignSelf={"center"}
m={1}>
<Tooltip title={value && value.path}>
<Typography variant={"caption"}
className={"mono"}>
{entity.id}
</Typography>
</Tooltip>
</Box>}
{!missingEntity && entity && value && <Box>
<Tooltip title={`See details for ${entity.id}`}>
<span>
<IconButton
onClick={seeEntityDetails}
size="large">
<KeyboardTabIcon/>
</IconButton>
</span>
</Tooltip>
</Box>}
{value && <Box>
<Tooltip title="Clear">
<span>
<IconButton
disabled={disabled}
onClick={disabled ? undefined : clearValue}
size="large">
<ClearIcon/>
</IconButton>
</span>
</Tooltip>
</Box>}
</Box>
{body}
</Box>
</Box>
);
}
return (
<FormControl error={showError} fullWidth>
<div
className={`${classes.root} ${disabled ? classes.disabled : ""}`}>
{schemaResolver && buildEntityView(schemaResolver)}
{collectionResolver && <ReferenceDialog open={open}
collectionResolver={collectionResolver}
multiselect={false}
path={path}
onClose={onClose}
onSingleEntitySelected={handleEntityClick}
/>}
</div>
{includeDescription &&
<FieldDescription property={property}/>}
{showError && <FormHelperText>{error}</FormHelperText>}
</FormControl>
);
}
Example #26
Source File: MapField.tsx From firecms with MIT License | 4 votes |
/**
* Field that renders the children property fields
*
* This is one of the internal components that get mapped natively inside forms
* and tables to the specified properties.
* @category Form fields
*/
export function MapField<T extends object>({
name,
value,
showError,
disabled,
property,
setValue,
tableMode,
includeDescription,
underlyingValueHasChanged,
context
}: FieldProps<T>) {
const pickOnlySomeKeys = property.config?.pickOnlySomeKeys || false;
if (!property.properties) {
throw Error(`You need to specify a 'properties' prop (or specify a custom field) in your map property ${name}`);
}
let mapProperties: Record<string, Property>;
if (!pickOnlySomeKeys) {
mapProperties = property.properties as Properties;
} else if (value) {
mapProperties = pick(property.properties as Properties,
...Object.keys(value)
.filter(key => key in property.properties!)
);
} else {
mapProperties = {};
}
useClearRestoreValue({
property,
value,
setValue
});
function buildPickKeysSelect() {
const keys = Object.keys(property.properties!)
.filter((key) => !value || !(key in value));
const handleAddProperty = (event: SelectChangeEvent) => {
setValue({
...value,
[event.target.value as string]: null
});
};
if (!keys.length) return <></>;
return <Box m={1}>
<FormControl fullWidth>
<InputLabel>Add property</InputLabel>
<Select
variant={"standard"}
value={""}
disabled={disabled}
onChange={handleAddProperty}>
{keys.map((key) => (
<MenuItem key={key} value={key}>
{(property.properties as Properties)[key].title || key}
</MenuItem>
))}
</Select>
</FormControl>
</Box>;
}
return (
<FormControl fullWidth error={showError}>
{!tableMode && <FormHelperText filled
required={property.validation?.required}>
<LabelWithIcon property={property}/>
</FormHelperText>}
<Paper elevation={0} variant={"outlined"} sx={(theme) => ({
elevation: 0,
padding: theme.spacing(2),
[theme.breakpoints.up("md")]: {
padding: theme.spacing(2)
}
})}>
<Grid container spacing={2}>
{Object.entries(mapProperties)
.filter(([_, property]) => !isHidden(property))
.map(([entryKey, childProperty], index) => {
return (
<Grid item
sm={12}
xs={12}
key={`map-${name}-${index}`}>
{
buildPropertyField<any, T>({
name: `${name}[${entryKey}]`,
disabled,
property: childProperty,
includeDescription,
underlyingValueHasChanged,
context,
tableMode,
partOfArray: false,
autoFocus: false,
shouldAlwaysRerender: false
})
}
</Grid>
);
}
)}
</Grid>
{pickOnlySomeKeys && buildPickKeysSelect()}
</Paper>
{includeDescription &&
<FieldDescription property={property}/>}
</FormControl>
);
}
Example #27
Source File: ArrayOneOfField.tsx From firecms with MIT License | 4 votes |
/**
* If the `oneOf` property is specified, this fields render each array entry as
* a `type` select and the corresponding field widget to the selected `type.
*
* This is one of the internal components that get mapped natively inside forms
* and tables to the specified properties.
* @category Form fields
*/
export function ArrayOneOfField<T extends Array<any>>({
name,
value,
error,
showError,
isSubmitting,
setValue,
tableMode,
property,
includeDescription,
underlyingValueHasChanged,
context,
disabled,
shouldAlwaysRerender
}: FieldProps<T>) {
if (!property.oneOf)
throw Error("ArrayOneOfField misconfiguration. Property `oneOf` not set");
useClearRestoreValue({
property,
value,
setValue
});
const [lastAddedId, setLastAddedId] = useState<number | undefined>();
const buildEntry = (index: number, internalId: number) => {
return <ArrayOneOfEntry
key={`array_one_of_${index}`}
name={`${name}[${index}]`}
index={index}
value={value[index]}
typeField={property.oneOf!.typeField ?? "type"}
valueField={property.oneOf!.valueField ?? "value"}
properties={property.oneOf!.properties}
autoFocus={internalId === lastAddedId}
context={context}/>;
};
return (
<FormControl fullWidth error={showError}>
{!tableMode && <FormHelperText filled
required={property.validation?.required}>
<LabelWithIcon property={property}/>
</FormHelperText>}
<Paper variant={"outlined"}
sx={(theme) => ({
elevation: 0,
padding: theme.spacing(2),
[theme.breakpoints.up("md")]: {
padding: theme.spacing(2)
}
})}>
<ArrayContainer value={value}
name={name}
buildEntry={buildEntry}
onInternalIdAdded={setLastAddedId}
disabled={isSubmitting || Boolean(property.disabled)}
includeAddButton={!property.disabled}/>
</Paper>
{includeDescription &&
<FieldDescription property={property}/>}
{showError &&
typeof error === "string" &&
<FormHelperText>{error}</FormHelperText>}
</FormControl>
);
}
Example #28
Source File: ArrayOfReferencesField.tsx From firecms with MIT License | 4 votes |
/**
* This field allows selecting multiple references.
*
* This is one of the internal components that get mapped natively inside forms
* and tables to the specified properties.
* @category Form fields
*/
export function ArrayOfReferencesField({
name,
value,
error,
showError,
isSubmitting,
tableMode,
property,
includeDescription,
setValue
}: ArrayOfReferencesFieldProps) {
const ofProperty: Property = property.of as Property;
if (ofProperty.dataType !== "reference") {
throw Error("ArrayOfReferencesField expected a property containing references");
}
const [open, setOpen] = React.useState(false);
const [onHover, setOnHover] = React.useState(false);
const selectedIds = value && Array.isArray(value) ? value.map((ref) => ref.id) : [];
useClearRestoreValue({
property,
value,
setValue
});
const navigationContext = useNavigation();
const collectionResolver: EntityCollectionResolver | undefined = useMemo(() => {
return ofProperty.path ? navigationContext.getCollectionResolver(ofProperty.path) : undefined;
}, [ofProperty.path]);
if (!collectionResolver) {
throw Error(`Couldn't find the corresponding collection for the path: ${ofProperty.path}`);
}
const onEntryClick = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const onMultipleEntitiesSelected = (entities: Entity<any>[]) => {
setValue(entities.map(e => getReferenceFrom(e)));
};
const buildEntry = (index: number, internalId: number) => {
const entryValue = value && value.length > index ? value[index] : undefined;
if (!entryValue)
return <div>Internal ERROR</div>;
return (
<div
onMouseEnter={() => setOnHover(true)}
onMouseMove={() => setOnHover(true)}
onMouseLeave={() => setOnHover(false)}>
<ReferencePreview
value={entryValue}
property={ofProperty}
onHover={onHover}
size={"regular"}
onClick={onEntryClick}/>
</div>
);
};
return (
<>
<FormControl fullWidth error={showError}>
{!tableMode && <FormHelperText filled
required={property.validation?.required}>
<LabelWithIcon property={property}/>
</FormHelperText>}
<Paper variant={"outlined"}
sx={(theme) => ({
elevation: 0,
padding: theme.spacing(2),
[theme.breakpoints.up("md")]: {
padding: theme.spacing(2)
}
})}>
{!collectionResolver && <ErrorView
error={"The specified collection does not exist. Check console"}/>}
{collectionResolver && <>
<ArrayContainer value={value}
name={name}
buildEntry={buildEntry}
disabled={isSubmitting}/>
<Box p={1}
justifyContent="center"
textAlign={"left"}>
<Button variant="outlined"
color="primary"
disabled={isSubmitting}
onClick={onEntryClick}>
Edit {property.title}
</Button>
</Box>
</>}
</Paper>
{includeDescription &&
<FieldDescription property={property}/>}
{showError &&
typeof error === "string" &&
<FormHelperText>{error}</FormHelperText>}
</FormControl>
{collectionResolver && ofProperty.path && <ReferenceDialog open={open}
multiselect={true}
collectionResolver={collectionResolver}
path={ofProperty.path}
onClose={onClose}
onMultipleEntitiesSelected={onMultipleEntitiesSelected}
selectedEntityIds={selectedIds}
/>}
</>
);
}
Example #29
Source File: ArrayEnumSelect.tsx From firecms with MIT License | 4 votes |
/**
* This fields renders a dropdown with multiple selection.
*
* This is one of the internal components that get mapped natively inside forms
* and tables to the specified properties.
* @category Form fields
*/
export function ArrayEnumSelect({
name,
value,
setValue,
error,
showError,
disabled,
property,
includeDescription,
autoFocus
}: FieldProps<EnumType[]>) {
const classes = formStyles();
if (!property.of) {
throw Error("Using wrong component ArrayEnumSelect");
}
if (property.of.dataType !== "string" && property.of.dataType !== "number") {
throw Error("Field misconfiguration: array field of type string or number");
}
const enumValues = property.of.config?.enumValues;
if (!enumValues) {
console.error(property);
throw Error("Field misconfiguration: array field of type string or number needs to have enumValues");
}
useClearRestoreValue({
property,
value,
setValue
});
const validValue = !!value && Array.isArray(value);
return (
<FormControl
variant="filled"
fullWidth
required={property.validation?.required}
error={showError}
>
<InputLabel id={`${name}-multiselect-label`}
classes={{
root: classes.inputLabel,
shrink: classes.shrinkInputLabel
}}>
<LabelWithIcon property={property}/>
</InputLabel>
<MuiSelect
multiple
sx={{
minHeight: "64px"
}}
variant={"filled"}
labelId={`${name}-multiselect-label`}
value={validValue ? value.map(v => v.toString()) : []}
autoFocus={autoFocus}
disabled={disabled}
onChange={(evt: any) => {
let newValue;
if (property.of?.dataType === "number")
newValue = evt.target.value ? evt.target.value.map((e: any) => parseFloat(e)) : [];
else
newValue = evt.target.value;
return setValue(
newValue
);
}}
renderValue={(selected: any) => (
<ArrayEnumPreview value={selected}
name={name}
enumValues={enumValues}
size={"regular"}/>
)}>
{enumToObjectEntries(enumValues)
.map(([enumKey, labelOrConfig]) => {
const checked = validValue && value.map(v => v.toString()).includes(enumKey.toString());
return (
<MenuItem key={`form-select-${name}-${enumKey}`}
value={enumKey}
disabled={isEnumValueDisabled(labelOrConfig)}
dense={true}>
<Checkbox checked={checked}/>
<ListItemText primary={
<EnumValuesChip
enumKey={enumKey}
enumValues={enumValues}
small={true}/>
}/>
</MenuItem>
);
})}
</MuiSelect>
{includeDescription &&
<FieldDescription property={property}/>}
{showError && <FormHelperText>{error}</FormHelperText>}
</FormControl>
);
}