diff --git a/spiffworkflow-frontend/src/themes/carbon/BaseInputTemplate/BaseInputTemplate.tsx b/spiffworkflow-frontend/src/themes/carbon/BaseInputTemplate/BaseInputTemplate.tsx index a3d225e6..eea1abe0 100644 --- a/spiffworkflow-frontend/src/themes/carbon/BaseInputTemplate/BaseInputTemplate.tsx +++ b/spiffworkflow-frontend/src/themes/carbon/BaseInputTemplate/BaseInputTemplate.tsx @@ -1,57 +1,80 @@ -import React from 'react'; // @ts-ignore import { TextInput } from '@carbon/react'; -import { getInputProps, WidgetProps } from '@rjsf/utils'; +import { + getInputProps, + FormContextType, + RJSFSchema, + StrictRJSFSchema, + WidgetProps, +} from '@rjsf/utils'; -function BaseInputTemplate({ - id, - placeholder, - required, - readonly, - disabled, - type, - label, - value, - onChange, - onBlur, - onFocus, - autofocus, - options, - schema, - uiSchema, - rawErrors = [], - registry, - ...textFieldProps -}: WidgetProps) { - const inputProps = getInputProps(schema, type, options); - // Now we need to pull out the step, min, max into an inner `inputProps` for material-ui - const { step, min, max, ...rest } = inputProps; - const otherProps = { - inputProps: { - step, - min, - max, - ...(schema.examples ? { list: `examples_${id}` } : undefined), - }, +import { useCallback } from 'react'; + +/** The `BaseInputTemplate` is the template to use to render the basic `` component for the `core` theme. + * It is used as the template for rendering many of the based widgets that differ by `type` and callbacks only. + * It can be customized/overridden for other themes or individual implementations as needed. + * + * @param props - The `WidgetProps` for this template + */ +export default function BaseInputTemplate< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any +>(props: WidgetProps) { + const { + id, + value, + readonly, + disabled, + autofocus, + label, + onBlur, + onFocus, + onChange, + required, + options, + schema, + uiSchema, + formContext, + 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, + ...getInputProps(schema, type, options), }; - const localOnChange = ({ - // eslint-disable-next-line no-shadow - target: { value }, - }: React.ChangeEvent) => { - onChange(value === '' ? options.emptyValue : value); - }; - const localOnBlur = ({ - // eslint-disable-next-line no-shadow - target: { value }, - }: React.FocusEvent) => onBlur(id, value); - const localOnFocus = ({ - // eslint-disable-next-line no-shadow - target: { value }, - }: React.FocusEvent) => onFocus(id, value); - const { schemaUtils } = registry; - const displayLabel = schemaUtils.getDisplayLabel(schema, uiSchema); + let inputValue; + if (inputProps.type === 'number' || inputProps.type === 'integer') { + inputValue = value || value === 0 ? value : ''; + } else { + inputValue = value == null ? '' : value; + } + + const _onChange = useCallback( + ({ target: { value } }: React.ChangeEvent) => + onChange(value === '' ? options.emptyValue : value), + [onChange, options] + ); + const _onBlur = useCallback( + ({ target: { value } }: React.FocusEvent) => + onBlur(id, value), + [onBlur, id] + ); + const _onFocus = useCallback( + ({ target: { value } }: React.FocusEvent) => + onFocus(id, value), + [onFocus, id] + ); let labelToUse = label; if (uiSchema && uiSchema['ui:title']) { @@ -59,39 +82,33 @@ function BaseInputTemplate({ } else if (schema && schema.title) { labelToUse = schema.title; } - if (required) { - labelToUse = `${labelToUse}*`; - } return ( <> 0} - onChange={localOnChange} - onBlur={localOnBlur} - onFocus={localOnFocus} + onChange={_onChange} + onBlur={_onBlur} + onFocus={_onFocus} // eslint-disable-next-line react/jsx-props-no-spreading - {...otherProps} + {...inputProps} /> - {schema.examples && ( - - {(schema.examples as string[]) - .concat(schema.default ? ([schema.default] as string[]) : []) - .map((example: any) => { - // eslint-disable-next-line jsx-a11y/control-has-associated-label - return