All files / packages/components/src file-input.web.tsx

88.46% Statements 23/26
66.66% Branches 4/6
80% Functions 8/10
91.66% Lines 22/24

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52                  23x 2x 2x 2x 2x   2x 2x 2x 2x 2x 2x         234x 280x 280x 17x     17x   280x       2x   2x 2x 2x           280x        
import React from "react";
 
import { promisifyEvent } from "~utils/promise";
 
export type Props = {
	onClickRef?: React.RefObject<() => void>;
	onFileUpdate?: (dataBlob: string) => void;
};
 
const convertFileToDataUrl = (file: File) => {
	const reader = new FileReader();
	return promisifyEvent<string>((listener, errorListener) => {
		const localListener = () => listener(reader.result as string);
		const localErrorListener = () =>
			errorListener(new Error("Problem converting file to data url"));
		reader.addEventListener("load", localListener, false);
		reader.addEventListener("error", localErrorListener);
		reader.readAsDataURL(file);
		return () => {
			reader.removeEventListener("load", localListener);
			reader.removeEventListener("error", localErrorListener);
		};
	});
};
 
export const FileInput: React.FC<Props> = ({ onClickRef, onFileUpdate }) => {
	const inputRef = React.useRef<HTMLInputElement>(null);
	React.useEffect(() => {
		Iif (!onClickRef) {
			return;
		}
		onClickRef.current = () => inputRef.current?.click();
	}, [onClickRef]);
	const onChange = React.useCallback<
		React.ChangeEventHandler<HTMLInputElement>
	>(
		(event) => {
			Eif (event.target.files && event.target.files.length !== 0) {
				// oxlint-disable-next-line typescript/no-non-null-assertion
				const file = event.target.files[0]!;
				void convertFileToDataUrl(file).then((dataUrl) =>
					onFileUpdate?.(dataUrl),
				);
			}
		},
		[onFileUpdate],
	);
	return (
		<input ref={inputRef} className="hidden" onChange={onChange} type="file" />
	);
};