package.src.components.FileUpload.FileUpload.tsx Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of react-core Show documentation
Show all versions of react-core Show documentation
This library provides a set of common React components for use with the PatternFly reference implementation.
The newest version!
import * as React from 'react';
import { DropzoneInputProps, DropzoneOptions, FileRejection, useDropzone } from 'react-dropzone';
import { FileUploadField, FileUploadFieldProps } from './FileUploadField';
import { readFile, fileReaderType } from '../../helpers/fileUtils';
import { DropEvent } from '../../helpers/typeUtils';
import { fromEvent } from 'file-selector';
export interface FileUploadProps
extends Omit<
FileUploadFieldProps,
'children' | 'onBrowseButtonClick' | 'onClearButtonClick' | 'isDragActive' | 'containerRef'
> {
/** Flag to allow editing of a text file's contents after it is selected from disk. */
allowEditingUploadedText?: boolean;
/** Aria-label for the text area. */
'aria-label'?: string;
/** Text for the browse button. */
browseButtonText?: string;
/** Additional children to render after (or instead of) the file preview. */
children?: React.ReactNode;
/** Additional classes added to the file upload container element. */
className?: string;
/** Text for the clear button. */
clearButtonText?: string;
/** Value to be shown in the read-only filename field. */
filename?: string;
/** Aria-label for the read-only filename field. */
filenameAriaLabel?: string;
/** Placeholder string to display in the empty filename field. */
filenamePlaceholder?: string;
/** Flag to hide the built-in preview of the file (where available). If true, you can use
* the children property to render an alternate preview.
*/
hideDefaultPreview?: boolean;
/** Unique id for the text area. Also used to generate ids for accessible labels. */
id: string;
/** Flag to show if the field is disabled. */
isDisabled?: boolean;
/** Flag to show if a file is being loaded. */
isLoading?: boolean;
/** Flag to show if the field is read only. */
isReadOnly?: boolean;
/** Flag to show if the field is required. */
isRequired?: boolean;
/** Callback for clicking on the file upload field text area. By default, prevents a click
* in the text area from opening file dialog.
*/
onClick?: (event: React.MouseEvent) => void;
/** Change event emitted from the hidden \ field associated with the component */
onFileInputChange?: (event: DropEvent, file: File) => void;
/** Aria-valuetext for the loading spinner. */
spinnerAriaValueText?: string;
/** What type of file. Determines whether 'onDataChange` is called and what is
* expected by the value property (a string for 'text' and 'dataURL', or a File object otherwise.
*/
type?: 'text' | 'dataURL';
/** Value to indicate if the field is modified to show that validation state.
* If set to success, field will be modified to indicate valid state.
* If set to error, field will be modified to indicate error state.
*/
validated?: 'success' | 'error' | 'default';
/** Value of the file's contents (string if text file, File object otherwise). */
value?: string | File;
// Props available in FileUpload but not FileUploadField:
/** Optional extra props to customize react-dropzone. */
dropzoneProps?: Partial;
/** Clear button was clicked. */
onClearClick?: React.MouseEventHandler;
/** On data changed - if type='text' or type='dataURL' and file was loaded it will call this method */
onDataChange?: (event: DropEvent, data: string) => void;
/** A callback for when the FileReader API fails. */
onReadFailed?: (event: DropEvent, error: DOMException, fileHandle: File) => void;
/** A callback for when a selected file finishes loading. */
onReadFinished?: (event: DropEvent, fileHandle: File) => void;
/** A callback for when a selected file starts loading. */
onReadStarted?: (event: DropEvent, fileHandle: File) => void;
/** Text area text changed. */
onTextChange?: (event: React.ChangeEvent, text: string) => void;
}
export const FileUpload: React.FunctionComponent = ({
id,
type,
value = type === fileReaderType.text || type === fileReaderType.dataURL ? '' : null,
filename = '',
children = null,
onFileInputChange = null,
onReadStarted = () => {},
onReadFinished = () => {},
onReadFailed = () => {},
onClearClick,
onClick = (event) => event.preventDefault(),
onTextChange,
onDataChange,
dropzoneProps = {},
...props
}: FileUploadProps) => {
const onDropAccepted = (acceptedFiles: File[], event: DropEvent) => {
if (acceptedFiles.length > 0) {
const fileHandle = acceptedFiles[0];
onFileInputChange?.(event, fileHandle);
if (type === fileReaderType.text || type === fileReaderType.dataURL) {
onReadStarted(event, fileHandle);
readFile(fileHandle, type as fileReaderType)
.then((data) => {
onReadFinished(event, fileHandle);
onDataChange?.(event, data as string);
})
.catch((error: DOMException) => {
onReadFailed(event, error, fileHandle);
onReadFinished(event, fileHandle);
onDataChange?.(event, '');
});
}
}
dropzoneProps.onDropAccepted && dropzoneProps.onDropAccepted(acceptedFiles, event);
};
const onDropRejected = (rejectedFiles: FileRejection[], event: DropEvent) => {
dropzoneProps.onDropRejected && dropzoneProps.onDropRejected(rejectedFiles, event);
};
const onClearButtonClick = (event: React.MouseEvent) => {
onClearClick?.(event);
setFileValue(null);
};
const { getRootProps, getInputProps, isDragActive, open, inputRef } = useDropzone({
noClick: true,
multiple: false,
...dropzoneProps,
onDropAccepted,
onDropRejected
});
const setFileValue = (filename: string) => {
inputRef.current.value = filename;
};
const oldInputProps = getInputProps();
const inputProps: DropzoneInputProps = {
...oldInputProps,
onChange: async (e: React.ChangeEvent) => {
oldInputProps.onChange?.(e);
const files = await fromEvent(e.nativeEvent);
if (files.length === 1) {
onFileInputChange?.(e, files[0] as File);
}
}
};
const rootProps = getRootProps({
...props,
tabIndex: null, // Omit the unwanted tabIndex from react-dropzone's getRootProps
id,
type,
filename,
value,
isDragActive,
onBrowseButtonClick: open,
onClearButtonClick,
onTextAreaClick: onClick,
onTextChange,
onClick,
refKey: 'containerRef'
});
return (
{children}
);
};
FileUpload.displayName = 'FileUpload';