mirror of
https://github.com/sartography/spiff-arena.git
synced 2025-01-28 02:05:52 +00:00
fixed error messaging a little bit for forms w/ burnettk cullerton
This commit is contained in:
parent
498292d354
commit
17e6605306
@ -1,57 +1,80 @@
|
|||||||
import React from 'react';
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { TextInput } from '@carbon/react';
|
import { TextInput } from '@carbon/react';
|
||||||
import { getInputProps, WidgetProps } from '@rjsf/utils';
|
import {
|
||||||
|
getInputProps,
|
||||||
|
FormContextType,
|
||||||
|
RJSFSchema,
|
||||||
|
StrictRJSFSchema,
|
||||||
|
WidgetProps,
|
||||||
|
} from '@rjsf/utils';
|
||||||
|
|
||||||
function BaseInputTemplate({
|
import { useCallback } from 'react';
|
||||||
id,
|
|
||||||
placeholder,
|
/** The `BaseInputTemplate` is the template to use to render the basic `<input>` component for the `core` theme.
|
||||||
required,
|
* It is used as the template for rendering many of the <input> based widgets that differ by `type` and callbacks only.
|
||||||
readonly,
|
* It can be customized/overridden for other themes or individual implementations as needed.
|
||||||
disabled,
|
*
|
||||||
type,
|
* @param props - The `WidgetProps` for this template
|
||||||
label,
|
*/
|
||||||
value,
|
export default function BaseInputTemplate<
|
||||||
onChange,
|
T = any,
|
||||||
onBlur,
|
S extends StrictRJSFSchema = RJSFSchema,
|
||||||
onFocus,
|
F extends FormContextType = any
|
||||||
autofocus,
|
>(props: WidgetProps<T, S, F>) {
|
||||||
options,
|
const {
|
||||||
schema,
|
id,
|
||||||
uiSchema,
|
value,
|
||||||
rawErrors = [],
|
readonly,
|
||||||
registry,
|
disabled,
|
||||||
...textFieldProps
|
autofocus,
|
||||||
}: WidgetProps) {
|
label,
|
||||||
const inputProps = getInputProps(schema, type, options);
|
onBlur,
|
||||||
// Now we need to pull out the step, min, max into an inner `inputProps` for material-ui
|
onFocus,
|
||||||
const { step, min, max, ...rest } = inputProps;
|
onChange,
|
||||||
const otherProps = {
|
required,
|
||||||
inputProps: {
|
options,
|
||||||
step,
|
schema,
|
||||||
min,
|
uiSchema,
|
||||||
max,
|
formContext,
|
||||||
...(schema.examples ? { list: `examples_${id}` } : undefined),
|
registry,
|
||||||
},
|
rawErrors,
|
||||||
|
type,
|
||||||
|
...rest
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
// Note: since React 15.2.0 we can't forward unknown element attributes, so we
|
||||||
|
// exclude the "options" and "schema" ones here.
|
||||||
|
if (!id) {
|
||||||
|
console.log('No id for', props);
|
||||||
|
throw new Error(`no id for props ${JSON.stringify(props)}`);
|
||||||
|
}
|
||||||
|
const inputProps = {
|
||||||
...rest,
|
...rest,
|
||||||
|
...getInputProps<T, S, F>(schema, type, options),
|
||||||
};
|
};
|
||||||
const localOnChange = ({
|
|
||||||
// eslint-disable-next-line no-shadow
|
|
||||||
target: { value },
|
|
||||||
}: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
onChange(value === '' ? options.emptyValue : value);
|
|
||||||
};
|
|
||||||
const localOnBlur = ({
|
|
||||||
// eslint-disable-next-line no-shadow
|
|
||||||
target: { value },
|
|
||||||
}: React.FocusEvent<HTMLInputElement>) => onBlur(id, value);
|
|
||||||
const localOnFocus = ({
|
|
||||||
// eslint-disable-next-line no-shadow
|
|
||||||
target: { value },
|
|
||||||
}: React.FocusEvent<HTMLInputElement>) => onFocus(id, value);
|
|
||||||
|
|
||||||
const { schemaUtils } = registry;
|
let inputValue;
|
||||||
const displayLabel = schemaUtils.getDisplayLabel(schema, uiSchema);
|
if (inputProps.type === 'number' || inputProps.type === 'integer') {
|
||||||
|
inputValue = value || value === 0 ? value : '';
|
||||||
|
} else {
|
||||||
|
inputValue = value == null ? '' : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const _onChange = useCallback(
|
||||||
|
({ target: { value } }: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
|
onChange(value === '' ? options.emptyValue : value),
|
||||||
|
[onChange, options]
|
||||||
|
);
|
||||||
|
const _onBlur = useCallback(
|
||||||
|
({ target: { value } }: React.FocusEvent<HTMLInputElement>) =>
|
||||||
|
onBlur(id, value),
|
||||||
|
[onBlur, id]
|
||||||
|
);
|
||||||
|
const _onFocus = useCallback(
|
||||||
|
({ target: { value } }: React.FocusEvent<HTMLInputElement>) =>
|
||||||
|
onFocus(id, value),
|
||||||
|
[onFocus, id]
|
||||||
|
);
|
||||||
|
|
||||||
let labelToUse = label;
|
let labelToUse = label;
|
||||||
if (uiSchema && uiSchema['ui:title']) {
|
if (uiSchema && uiSchema['ui:title']) {
|
||||||
@ -59,39 +82,33 @@ function BaseInputTemplate({
|
|||||||
} else if (schema && schema.title) {
|
} else if (schema && schema.title) {
|
||||||
labelToUse = schema.title;
|
labelToUse = schema.title;
|
||||||
}
|
}
|
||||||
if (required) {
|
|
||||||
labelToUse = `${labelToUse}*`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TextInput
|
<TextInput
|
||||||
id={id}
|
id={id}
|
||||||
name={id}
|
name={id}
|
||||||
placeholder={placeholder}
|
labelText={labelToUse}
|
||||||
labelText={displayLabel ? labelToUse : false}
|
|
||||||
autoFocus={autofocus}
|
autoFocus={autofocus}
|
||||||
disabled={disabled || readonly}
|
disabled={disabled || readonly}
|
||||||
value={value || value === 0 ? value : ''}
|
value={value || value === 0 ? value : ''}
|
||||||
error={rawErrors.length > 0}
|
onChange={_onChange}
|
||||||
onChange={localOnChange}
|
onBlur={_onBlur}
|
||||||
onBlur={localOnBlur}
|
onFocus={_onFocus}
|
||||||
onFocus={localOnFocus}
|
|
||||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||||
{...otherProps}
|
{...inputProps}
|
||||||
/>
|
/>
|
||||||
{schema.examples && (
|
{Array.isArray(schema.examples) && (
|
||||||
<datalist id={`examples_${id}`}>
|
<datalist key={`datalist_${id}`} id={`examples_${id}`}>
|
||||||
{(schema.examples as string[])
|
{[
|
||||||
.concat(schema.default ? ([schema.default] as string[]) : [])
|
...new Set(
|
||||||
.map((example: any) => {
|
schema.examples.concat(schema.default ? [schema.default] : [])
|
||||||
// eslint-disable-next-line jsx-a11y/control-has-associated-label
|
),
|
||||||
return <option key={example} value={example} />;
|
].map((example: any) => (
|
||||||
})}
|
<option key={example} value={example} />
|
||||||
|
))}
|
||||||
</datalist>
|
</datalist>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default BaseInputTemplate;
|
|
||||||
|
@ -1,34 +1,16 @@
|
|||||||
import React from 'react';
|
|
||||||
import ErrorIcon from '@mui/icons-material/Error';
|
|
||||||
import Box from '@mui/material/Box';
|
|
||||||
import List from '@mui/material/List';
|
|
||||||
import ListItem from '@mui/material/ListItem';
|
|
||||||
import ListItemIcon from '@mui/material/ListItemIcon';
|
|
||||||
import ListItemText from '@mui/material/ListItemText';
|
|
||||||
import Paper from '@mui/material/Paper';
|
|
||||||
import Typography from '@mui/material/Typography';
|
|
||||||
import { ErrorListProps } from '@rjsf/utils';
|
import { ErrorListProps } from '@rjsf/utils';
|
||||||
|
// @ts-ignore
|
||||||
|
import { Tag } from '@carbon/react';
|
||||||
|
|
||||||
function ErrorList({ errors }: ErrorListProps) {
|
function ErrorList({ errors }: ErrorListProps) {
|
||||||
return (
|
if (errors) {
|
||||||
<Paper elevation={2}>
|
return (
|
||||||
<Box mb={2} p={2}>
|
<Tag type="red" size="md" title="Fill Required Fields">
|
||||||
<Typography variant="h6">Errors</Typography>
|
Please fill out required fields
|
||||||
<List dense>
|
</Tag>
|
||||||
{errors.map((error, i: number) => {
|
);
|
||||||
return (
|
}
|
||||||
<ListItem key={i}>
|
return null;
|
||||||
<ListItemIcon>
|
|
||||||
<ErrorIcon color="error" />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary={error.stack} />
|
|
||||||
</ListItem>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</List>
|
|
||||||
</Box>
|
|
||||||
</Paper>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ErrorList;
|
export default ErrorList;
|
||||||
|
@ -1,29 +1,9 @@
|
|||||||
import React from 'react';
|
|
||||||
import { FieldErrorProps } from '@rjsf/utils';
|
import { FieldErrorProps } from '@rjsf/utils';
|
||||||
import ListItem from '@mui/material/ListItem';
|
|
||||||
import FormHelperText from '@mui/material/FormHelperText';
|
|
||||||
import List from '@mui/material/List';
|
|
||||||
|
|
||||||
/** The `FieldErrorTemplate` component renders the errors local to the particular field
|
/** The `FieldErrorTemplate` component renders the errors local to the particular field
|
||||||
*
|
*
|
||||||
* @param props - The `FieldErrorProps` for the errors being rendered
|
* @param props - The `FieldErrorProps` for the errors being rendered
|
||||||
*/
|
*/
|
||||||
export default function FieldErrorTemplate(props: FieldErrorProps) {
|
export default function FieldErrorTemplate(_props: FieldErrorProps) {
|
||||||
const { errors = [], idSchema } = props;
|
return null;
|
||||||
if (errors.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const id = `${idSchema.$id}__error`;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<List dense disablePadding>
|
|
||||||
{errors.map((error, i: number) => {
|
|
||||||
return (
|
|
||||||
<ListItem key={i} disableGutters>
|
|
||||||
<FormHelperText id={id}>{error}</FormHelperText>
|
|
||||||
</ListItem>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</List>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user