import type { ChangeEvent } from 'react'; import type { FileInfoType, FormContextType, Registry, RJSFSchema, StrictRJSFSchema, UIOptionsType, WidgetProps, } from '@rjsf/utils'; import { getTemplate, TranslatableString, useFileWidgetProps } from '@rjsf/utils'; import { Markdown } from 'markdown-to-jsx/react'; function FileInfoPreview({ fileInfo, registry, }: { fileInfo: FileInfoType; registry: Registry; }) { const { translateString } = registry; const { dataURL, type, name } = fileInfo; if (!dataURL) { return null; } const previewLabel = translateString(TranslatableString.PreviewLabel); // If type is JPEG or PNG then show image preview. // Originally, any type of image was supported, but this was changed into a whitelist // since SVGs and animated GIFs are also images, which are generally considered a security risk. if (['image/jpeg', 'image/png'].includes(type)) { return {previewLabel}; } // otherwise, let users download file return ( <> {' '} {previewLabel} ); } function FilesInfo({ filesInfo, registry, preview, onRemove, options, }: { filesInfo: FileInfoType[]; registry: Registry; preview?: boolean; onRemove: (index: number) => void; options: UIOptionsType; }) { if (filesInfo.length === 0) { return null; } const { translateString } = registry; const { RemoveButton } = getTemplate<'ButtonTemplates', T, S, F>('ButtonTemplates', registry, options); return (
    {filesInfo.map((fileInfo, key) => { const { name, size, type } = fileInfo; const handleRemove = () => onRemove(key); return ( // oxlint-disable-next-line react/no-array-index-key
  • {translateString(TranslatableString.FilesInfo, [name, type, String(size)])} {preview && fileInfo={fileInfo} registry={registry} />}
  • ); })}
); } /** * The `FileWidget` is a widget for rendering file upload fields. * It is typically used with a string property with data-url format. */ function FileWidget( props: WidgetProps, ) { const { disabled, readonly, required, multiple, onChange, value, options, registry } = props; const { filesInfo, handleChange, handleRemove } = useFileWidgetProps(value, onChange, multiple); const BaseInputTemplate = getTemplate<'BaseInputTemplate', T, S, F>('BaseInputTemplate', registry, options); const handleOnChangeEvent = (event: ChangeEvent) => { if (event.target.files) { // handleChange is async; DOM event handlers are void-returning, so we intentionally don't await // oxlint-disable-next-line no-floating-promises, no-void void handleChange(event.target.files); } }; return (
filesInfo={filesInfo} onRemove={handleRemove} registry={registry} preview={options.filePreview} options={options} />
); } export default FileWidget;