[Feature Request] File Uplaod #1814
Replies: 14 comments 7 replies
-
Is this feature being developed? |
Beta Was this translation helpful? Give feedback.
-
Found myself wanting this feature too; here's something I quickly whipped up, maybe somebody can find it useful. It's a file upload button that also supports drag & drop, though this code can also be used as a starting point for other components like a drop box. Implementation (CC0)'use client';
import { Button, ButtonProps } from '@nextui-org/react';
import { useCallback, useRef, useState } from 'react';
import { twMerge } from 'tailwind-merge';
const isAllFiles = (dt: DataTransfer) =>
dt.types.every(t => t === 'Files' || t === 'application/x-moz-file');
const doesAccept = (type: string, accept?: string) => {
if (!accept) {
return true;
}
const acceptList = accept.split(',').map(c => c.trim());
let cond = false;
for (const acceptor of acceptList) {
if (acceptor.endsWith('*')) {
cond ||= type.startsWith(acceptor.slice(0, -1));
} else {
cond ||= type === acceptor;
}
}
return cond;
};
const isEventAllowed = <T extends HTMLElement>(e: React.DragEvent<T>, accept: string | undefined, multiple: boolean) => {
if (!isAllFiles(e.dataTransfer)) {
return false;
}
const items = Array.from(e.dataTransfer.items);
if (items.length === 0 || (!multiple && items.length > 1)) {
return false;
}
return items.every(c => doesAccept(c.type, accept));
};
export default function FileUploadButton(
{ accept, onUpload, acceptProps = { color: 'primary' }, rejectProps = { color: 'danger' }, multiple = false, classNames, className, ...props }:
ButtonProps & {
classNames?: { wrapper?: string; button?: string; };
onUpload?: (files: File[]) => void;
acceptProps?: ButtonProps,
rejectProps?: ButtonProps,
accept?: string;
multiple?: boolean;
}
) {
const inputRef = useRef<HTMLInputElement | null>(null);
const [ acceptance, setAcceptance ] = useState<null | 'ACCEPT' | 'REJECT'>(null);
const onDragEnter = useCallback((e: React.DragEvent<HTMLButtonElement>) => {
if (isEventAllowed(e, accept, multiple)) {
setAcceptance('ACCEPT');
} else {
setAcceptance('REJECT');
}
}, [ accept, multiple, setAcceptance ]);
const onDragOver = useCallback((e: React.DragEvent<HTMLButtonElement>) => {
e.preventDefault();
if (isEventAllowed(e, accept, multiple)) {
setAcceptance('ACCEPT');
} else {
setAcceptance('REJECT');
}
}, [ accept, multiple, setAcceptance ]);
const onDragFinish = useCallback((e: React.DragEvent<HTMLButtonElement>) => {
setAcceptance(null);
}, [ setAcceptance ]);
const onDrop = useCallback((e: React.DragEvent<HTMLButtonElement>) => {
e.preventDefault();
e.persist();
e.stopPropagation();
if (isEventAllowed(e, accept, multiple)) {
const items = Array.from(e.dataTransfer.items);
if (items.length) {
onUpload?.(items.map(c => c.getAsFile()!));
}
}
setAcceptance(null);
}, [ accept, multiple, onUpload, setAcceptance ]);
const onFileChosen = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
onUpload?.(Array.from(e.target.files!));
}, [ onUpload ]);
const onButtonPress = useCallback(() => {
inputRef.current?.click();
}, [ inputRef ]);
return <form className={classNames?.wrapper}>
<label htmlFor='_upload'>
<Button {...props}
{...(acceptance === 'ACCEPT' ? acceptProps : acceptance === 'REJECT' ? rejectProps : {})}
className={twMerge(
className,
classNames?.button,
acceptance === 'ACCEPT'
? acceptProps?.className
: acceptance === 'REJECT'
? rejectProps?.className
: null
)}
onPress={onButtonPress}
onDragEnter={onDragEnter}
onDragOver={onDragOver}
onDragEnd={onDragFinish}
onDragLeave={onDragFinish}
onDrop={onDrop}
/>
</label>
<input
type='file'
role='presentation'
name='_upload'
ref={inputRef}
onChange={onFileChosen}
accept={accept}
multiple={multiple}
className='hidden'
/>
</form>;
} Example usage: <FileUploadButton
size='lg'
accept='image/*'
startContent={<PiUploadSimpleBold />}
rejectProps={{ color: 'danger', startContent: <PiXCircleBold /> }}
onUpload={files => {
console.log(files[0]);
}}
>
Upload
</FileUploadButton> |
Beta Was this translation helpful? Give feedback.
-
I want this |
Beta Was this translation helpful? Give feedback.
-
Has this been worked on at all anytime recently? Just curious... Though I think it's kind of funny NextUI doesn't have a file input system |
Beta Was this translation helpful? Give feedback.
This comment was marked as off-topic.
This comment was marked as off-topic.
-
@jrgarciadev @wingkwong So? Are you gonna add this feat? I'm willing to develop it. Let me know what you think. |
Beta Was this translation helpful? Give feedback.
-
Is your feature request related to a problem? Please describe.
In today's online world, images, photos, avatars, text files are very important. It's a pity that the next ui library, which I love and enjoy using, doesn't have a file upload component. I hope it comes as soon as possible.
Describe the solution you'd like
Describe alternatives you've considered
Ant Design Upload
Screenshots or Videos
No response
Beta Was this translation helpful? Give feedback.
All reactions