Skip to content

Instantly share code, notes, and snippets.

@estrattonbailey
Created March 25, 2020 16:47
Show Gist options
  • Save estrattonbailey/b6912c704454478f57f7cb7657d8ebad to your computer and use it in GitHub Desktop.
Save estrattonbailey/b6912c704454478f57f7cb7657d8ebad to your computer and use it in GitHub Desktop.
Enhanced Dropzone - react-dropzone
import * as React from 'react';
import { useDropzone, DropzoneProps, DropzoneState } from 'react-dropzone';
import { Omit } from '@utils/typescript';
import Box from '@components/Box';
import { Button } from '@components/Button';
import { H5, P } from '@components/Typography';
import IconCircleCheckFull from '@icons/CircleCheckFull';
type EnhancedDropzoneState = DropzoneState & {
files: File[];
removeFile(file: File): void;
};
const Context = React.createContext<EnhancedDropzoneState>(
{} as EnhancedDropzoneState
);
export function Provider({
children,
onUpdate,
...options
}: Omit<DropzoneProps, 'children'> & {
children: React.ReactNode | React.ReactNode[];
onUpdate?(files: File[]): void;
}) {
const [files, setFiles] = React.useState<File[]>([]);
const state = useDropzone({
...options,
onDropAccepted(acceptedFiles) {
setFiles(acceptedFiles);
if (onUpdate) onUpdate(acceptedFiles);
},
});
const removeFile = React.useCallback(
file => {
const next = files.filter(f => f !== file);
setFiles(next);
if (onUpdate) onUpdate(next);
},
[files]
);
return (
<Context.Provider
value={{
...state,
files,
removeFile,
}}
>
{children}
</Context.Provider>
);
}
export function Zone({
children,
}: {
children?(state: EnhancedDropzoneState): React.ReactNode | React.ReactNode[];
}) {
const state = React.useContext(Context);
const isActive = state.isDragActive || state.isFocused;
return (
<div
{...state.getRootProps({
style: {
position: 'relative',
},
})}
>
<input {...state.getInputProps()} />
{children ? (
children(state)
) : (
<Box
display="flex"
alignItems="center"
justifyContent="center"
p="lg"
bg="background"
border="1px dashed"
borderColor={
isActive || Boolean(state.files.length) ? 'primary' : 'outline'
}
borderRadius={1}
>
<Box textAlign="center">
<P mb="xxs" fontSize={0} color="secondary">
Drop file(s) here or
</P>
<Button appearance="secondary" size="small">
Upload
</Button>
</Box>
</Box>
)}
</div>
);
}
export function Files() {
const state = React.useContext(Context);
return (
<Box as="ul" py="xs">
{state.files.map(file => (
<Box
key={file.lastModified}
as="li"
py="xs"
px="sm"
display="flex"
alignItems="center"
justifyContent="space-between"
>
<Box pr="sm" display="flex" alignItems="center">
<IconCircleCheckFull
width="16px"
height="16px"
mr="xs"
color="success"
/>
<H5 color="secondary">{file.name}</H5>
</Box>
<Button
appearance="secondary"
size="small"
onClick={() => {
state.removeFile(file);
}}
>
Remove
</Button>
</Box>
))}
</Box>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment