Skip to content

Commit 7d8d23d

Browse files
committed
feat: allow user to drop lottie or json file
1 parent 75c69a9 commit 7d8d23d

2 files changed

Lines changed: 92 additions & 11 deletions

File tree

src/AnimationFileInput.tsx

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { css } from '@linaria/core';
22
import React, { useEffect, useState } from 'react';
3+
import { GlobalDropzone } from './AnimationFileInputDropzone';
34

45
export interface AnimationFileInputProps {
56
onFileChange: (url: string) => void;
@@ -41,7 +42,6 @@ const AnimationFileButton: React.FC<AnimationFileButtonProps> = ({ onFileChange,
4142
}
4243
}, []);
4344

44-
4545
const getUrl = async (file?: File | Response) => {
4646
setLoading(true);
4747
try {
@@ -91,17 +91,23 @@ const AnimationFileButton: React.FC<AnimationFileButtonProps> = ({ onFileChange,
9191

9292

9393
return (
94-
<label className={cssButton} tabIndex={0}>
95-
{loading ? "Processing..." : "Load your own animation"}
96-
<input
97-
type="file"
98-
style={{ display: "none" }}
99-
accept=".json,.zip,.lottie"
100-
onChange={(e) => {
101-
getUrl(e.currentTarget.files?.[0])
102-
}}
94+
<>
95+
<label className={cssButton} tabIndex={0}>
96+
{loading ? "Processing..." : "Load your own animation"}
97+
<input
98+
type="file"
99+
style={{ display: "none" }}
100+
accept=".json,.zip,.lottie"
101+
onChange={(e) => {
102+
getUrl(e.currentTarget.files?.[0])
103+
}}
104+
/>
105+
</label>
106+
<GlobalDropzone
107+
onFileDrop={getUrl}
103108
/>
104-
</label>
109+
</>
110+
105111
)
106112
};
107113

src/AnimationFileInputDropzone.tsx

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { styled } from "@linaria/react";
2+
import { useEffect, useState } from "react";
3+
4+
export interface GlobalDropzoneProps {
5+
onFileDrop: (file: File) => void;
6+
}
7+
8+
export const GlobalDropzone = ({ onFileDrop }: GlobalDropzoneProps) => {
9+
const [state, setState] = useState("");
10+
useEffect(() => {
11+
const dragend = () => {
12+
setState("");
13+
};
14+
15+
const dragover = (e: DragEvent) => {
16+
setState("over");
17+
console.log(e.dataTransfer, e.dataTransfer?.files[0]);
18+
e.preventDefault();
19+
e.stopPropagation();
20+
};
21+
22+
const drop = async (e: DragEvent) => {
23+
setState("");
24+
e.preventDefault();
25+
e.stopPropagation();
26+
27+
if (e.dataTransfer && e.dataTransfer.files.length > 0) {
28+
const file = e.dataTransfer.files[0];
29+
onFileDrop(file);
30+
}
31+
};
32+
33+
const ab = new AbortController();
34+
35+
window.addEventListener('dragleave', dragend, { signal: ab.signal });
36+
window.addEventListener('dragover', dragover, { signal: ab.signal });
37+
window.addEventListener('drop', drop, { signal: ab.signal });
38+
39+
return () => {
40+
ab.abort();
41+
};
42+
}, []);
43+
44+
return (
45+
<DropZoneEffect
46+
data-drop-state={state}
47+
>
48+
Drop file here
49+
</DropZoneEffect>
50+
)
51+
}
52+
53+
const DropZoneEffect = styled.div`
54+
position: fixed;
55+
inset: 0;
56+
width: 100vw;
57+
height: 100vh;
58+
pointer-events: none;
59+
background: rgba(240, 240, 240, 1);
60+
transition-property: backdrop-filter, opacity;
61+
transition-duration: 0.1s;
62+
transition-timing-function: ease-in-out;
63+
opacity: 0;
64+
65+
font-size: 2rem;
66+
67+
display: flex;
68+
justify-content: center;
69+
align-items: center;
70+
&[data-drop-state="over"] {
71+
opacity: 0.9;
72+
backdrop-filter: blur(2px);
73+
transition-duration: 0.3s;
74+
}
75+
`;

0 commit comments

Comments
 (0)