From 70d7c7370f0f8c714e912fec7551d96a2a1d11a6 Mon Sep 17 00:00:00 2001 From: Appie Date: Fri, 24 Jan 2025 21:08:23 +0100 Subject: [PATCH] Fixed file accept attribute not working on mui and chakra-ui. (#4457) --- CHANGELOG.md | 5 +++++ .../src/BaseInputTemplate/BaseInputTemplate.tsx | 17 ++++++----------- packages/utils/src/getInputProps.ts | 4 ++++ packages/utils/src/types.ts | 2 ++ packages/utils/test/getInputProps.test.ts | 11 +++++++++-- 5 files changed, 26 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0be4c35b7..358c85bcc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,11 @@ should change the heading of the (upcoming) version to include a major version b ## @rjsf/utils - switch `lodash.isEqualWith` to `fast-equals.createCustomEqual` providing `areFunctionsEqual` assuming any functions are equal. +- Fixed issue with file accept attribute, fixing [#4404](https://github.com/rjsf-team/react-jsonschema-form/issues/4404). + +## @rjsf/mui + +- Fixed issue with file accept attribute, fixing [#4404](https://github.com/rjsf-team/react-jsonschema-form/issues/4404). # 5.24.1 diff --git a/packages/mui/src/BaseInputTemplate/BaseInputTemplate.tsx b/packages/mui/src/BaseInputTemplate/BaseInputTemplate.tsx index 9c3f0a706a..4eb8fea899 100644 --- a/packages/mui/src/BaseInputTemplate/BaseInputTemplate.tsx +++ b/packages/mui/src/BaseInputTemplate/BaseInputTemplate.tsx @@ -53,16 +53,8 @@ export default function BaseInputTemplate< } = props; 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: examplesId(id) } : undefined), - }, - ...rest, - }; + const { step, min, max, accept, ...rest } = inputProps; + const htmlInputProps = { step, min, max, accept, ...(schema.examples ? { list: examplesId(id) } : undefined) }; const _onChange = ({ target: { value } }: ChangeEvent) => onChange(value === '' ? options.emptyValue : value); const _onBlur = ({ target }: FocusEvent) => onBlur(id, target && target.value); @@ -84,7 +76,10 @@ export default function BaseInputTemplate< autoFocus={autofocus} required={required} disabled={disabled || readonly} - {...otherProps} + slotProps={{ + htmlInput: htmlInputProps, + }} + {...rest} value={value || value === 0 ? value : ''} error={rawErrors.length > 0} onChange={onChangeOverride || _onChange} diff --git a/packages/utils/src/getInputProps.ts b/packages/utils/src/getInputProps.ts index 39d31e0e87..6ebb673322 100644 --- a/packages/utils/src/getInputProps.ts +++ b/packages/utils/src/getInputProps.ts @@ -51,5 +51,9 @@ export default function getInputProps< inputProps.autoComplete = options.autocomplete; } + if (options.accept) { + inputProps.accept = options.accept as string; + } + return inputProps; } diff --git a/packages/utils/src/types.ts b/packages/utils/src/types.ts index 359d6bb45c..2d6c8335c3 100644 --- a/packages/utils/src/types.ts +++ b/packages/utils/src/types.ts @@ -150,6 +150,8 @@ export type InputPropsType = Omit & { step?: number | 'any'; /** Specifies the `autoComplete` value for an element */ autoComplete?: HTMLInputElement['autocomplete']; + /** Specifies a filter for what file types the user can upload. */ + accept?: HTMLInputElement['accept']; }; /** Type describing an id used for a field in the `IdSchema` */ diff --git a/packages/utils/test/getInputProps.test.ts b/packages/utils/test/getInputProps.test.ts index 8708083730..0ad15f22f9 100644 --- a/packages/utils/test/getInputProps.test.ts +++ b/packages/utils/test/getInputProps.test.ts @@ -1,16 +1,23 @@ -import { getInputProps, RJSFSchema } from '../src'; +import { getInputProps, RJSFSchema, UIOptionsType } from '../src'; describe('getInputProps', () => { it('returns type=text when no other data is passed', () => { expect(getInputProps({})).toEqual({ type: 'text' }); }); it('returns type and autoComplete from options when provided', () => { - const options = { inputType: 'password', autocomplete: 'on' }; + const options: UIOptionsType = { inputType: 'password', autocomplete: 'on' }; expect(getInputProps({}, 'text', options)).toEqual({ type: options.inputType, autoComplete: options.autocomplete, }); }); + it('returns type and accept from options when provided', () => { + const options: UIOptionsType = { accept: '.pdf' }; + expect(getInputProps({}, 'file', options)).toEqual({ + type: 'file', + accept: options.accept, + }); + }); it('returns type=defaultType even when schema has type', () => { const schema: RJSFSchema = { type: 'number',