@dev-codergautam/drag-and-drop-uploader 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +21 -0
- package/readme.md +123 -0
- package/src/index.js +110 -0
- package/src/styles.css +71 -0
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dev-codergautam/drag-and-drop-uploader",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A lightweight drag-and-drop file uploader with previews.",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"files": [
|
|
8
|
+
"src"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"upload",
|
|
15
|
+
"drag-drop",
|
|
16
|
+
"preview",
|
|
17
|
+
"vanilla-js"
|
|
18
|
+
],
|
|
19
|
+
"author": "Your Name",
|
|
20
|
+
"license": "MIT"
|
|
21
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
A good `README.md` is the "front door" of your project. It needs to tell developers exactly what the package does, how to install it, and—most importantly—how to get it running in 60 seconds.
|
|
2
|
+
|
|
3
|
+
Here is a professional, well-structured `README.md` tailored for your **@dev-codergautam/drag-dropuploader** package.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# @dev-codergautam/drag-dropuploader
|
|
8
|
+
|
|
9
|
+
A lightweight, zero-dependency Vanilla JavaScript library for creating beautiful drag-and-drop file upload zones with real-time image previews.
|
|
10
|
+
|
|
11
|
+
## 🚀 Features
|
|
12
|
+
|
|
13
|
+
* **Drag & Drop Support**: Seamlessly handle file drops.
|
|
14
|
+
* **Clipboard Integration**: Supports pasting images directly from the clipboard.
|
|
15
|
+
* **Live Previews**: Automatically generates and displays thumbnails for images.
|
|
16
|
+
* **State Management**: Easily retrieve the current list of files for form submission.
|
|
17
|
+
* **Customizable**: Filter by file types and hook into update events.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 📦 Installation
|
|
22
|
+
|
|
23
|
+
Install the package via NPM:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install @dev-codergautam/drag-dropuploader
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 🛠 Usage
|
|
33
|
+
|
|
34
|
+
### 1. Vanilla JavaScript
|
|
35
|
+
|
|
36
|
+
First, create a container in your HTML:
|
|
37
|
+
|
|
38
|
+
```html
|
|
39
|
+
<div id="my-uploader"></div>
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Then, initialize the uploader in your JavaScript file:
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
import SimpleUploader from '@dev-codergautam/drag-dropuploader';
|
|
47
|
+
import '@dev-codergautam/drag-dropuploader/src/styles.css';
|
|
48
|
+
|
|
49
|
+
const uploader = new SimpleUploader('#my-uploader', {
|
|
50
|
+
allowedTypes: ['image/jpeg', 'image/png'],
|
|
51
|
+
onFilesUpdate: (files) => {
|
|
52
|
+
console.log("Files updated:", files);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// To get the files when submitting a form:
|
|
57
|
+
const files = uploader.getFiles();
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 2. React (Vite) Implementation
|
|
62
|
+
|
|
63
|
+
Since this is a DOM-based library, use the `useEffect` hook to initialize it.
|
|
64
|
+
|
|
65
|
+
```jsx
|
|
66
|
+
import { useEffect } from 'react';
|
|
67
|
+
import SimpleUploader from '@dev-codergautam/drag-dropuploader';
|
|
68
|
+
import '@dev-codergautam/drag-dropuploader/src/styles.css';
|
|
69
|
+
|
|
70
|
+
export default function UploaderComponent() {
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
const uploader = new SimpleUploader('#uploader-container', {
|
|
73
|
+
onFilesUpdate: (files) => console.log(files)
|
|
74
|
+
});
|
|
75
|
+
}, []);
|
|
76
|
+
|
|
77
|
+
return <div id="uploader-container"></div>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## ⚙️ Configuration Options
|
|
85
|
+
|
|
86
|
+
| Option | Type | Default | Description |
|
|
87
|
+
| --- | --- | --- | --- |
|
|
88
|
+
| `allowedTypes` | `Array` | `['image/']` | Array of MIME types or prefixes to allow. |
|
|
89
|
+
| `onFilesUpdate` | `Function` | `null` | Callback function triggered whenever files are added or removed. |
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 📖 API Methods
|
|
94
|
+
|
|
95
|
+
| Method | Description |
|
|
96
|
+
| --- | --- |
|
|
97
|
+
| `.getFiles()` | Returns an `Array` of the currently selected `File` objects. |
|
|
98
|
+
| `.removeFile(file)` | Removes a specific file object from the internal state and updates the UI. |
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 🎨 Custom Styling
|
|
103
|
+
|
|
104
|
+
The package comes with default styles, but you can override them in your own CSS. Key classes include:
|
|
105
|
+
|
|
106
|
+
* `.upload-container`: The main dropzone area.
|
|
107
|
+
* `.drag-over`: Applied to the container when a file is being hovered over it.
|
|
108
|
+
* `.image-preview-wrapper`: The wrapper for each individual image thumbnail.
|
|
109
|
+
* `.remove-icon`: The "X" button used to delete a preview.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## 📄 License
|
|
114
|
+
|
|
115
|
+
MIT © [dev-codergautam](https://www.google.com/search?q=https://github.com/dev-codergautam)
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
### Pro-Tip for your GitHub:
|
|
120
|
+
|
|
121
|
+
Include a **GIF** or a **screenshot** at the top of the README! Developers love seeing the UI in action before they install a package.
|
|
122
|
+
|
|
123
|
+
**Would you like me to help you write a `.gitignore` file so you don't accidentally upload your `node_modules` to GitHub?**
|
package/src/index.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
export default class SimpleUploader {
|
|
2
|
+
constructor(containerSelector, options = {}) {
|
|
3
|
+
this.container = document.querySelector(containerSelector);
|
|
4
|
+
this.options = {
|
|
5
|
+
allowedTypes: options.allowedTypes || ["image/"],
|
|
6
|
+
onFilesUpdate: options.onFilesUpdate || null,
|
|
7
|
+
...options,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
this.selectedFiles = [];
|
|
11
|
+
this.init();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
init() {
|
|
15
|
+
this.renderBaseHTML();
|
|
16
|
+
this.setupEventListeners();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
renderBaseHTML() {
|
|
20
|
+
this.container.classList.add("upload-container");
|
|
21
|
+
this.container.innerHTML = `
|
|
22
|
+
<p id="prompt-text">Drag & drop files, paste, or <b>click to browse</b></p>
|
|
23
|
+
<input type="file" id="file-input" multiple hidden />
|
|
24
|
+
<div id="preview-container"></div>
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
this.promptText = this.container.querySelector("#prompt-text");
|
|
28
|
+
this.fileInput = this.container.querySelector("#file-input");
|
|
29
|
+
this.previewContainer = this.container.querySelector("#preview-container");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
setupEventListeners() {
|
|
33
|
+
// Click to browse
|
|
34
|
+
this.promptText.addEventListener("click", () => this.fileInput.click());
|
|
35
|
+
|
|
36
|
+
this.fileInput.addEventListener("change", (e) => {
|
|
37
|
+
this.handleFiles(e.target.files);
|
|
38
|
+
e.target.value = "";
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Drag and Drop
|
|
42
|
+
["dragenter", "dragover", "dragleave", "drop"].forEach((name) => {
|
|
43
|
+
this.container.addEventListener(name, (e) => {
|
|
44
|
+
e.preventDefault();
|
|
45
|
+
e.stopPropagation();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
this.container.addEventListener("dragover", () => this.container.classList.add("drag-over"));
|
|
50
|
+
this.container.addEventListener("dragleave", () => this.container.classList.remove("drag-over"));
|
|
51
|
+
this.container.addEventListener("drop", (e) => {
|
|
52
|
+
this.container.classList.remove("drag-over");
|
|
53
|
+
this.handleFiles(e.dataTransfer.files);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Paste
|
|
57
|
+
window.addEventListener("paste", (e) => {
|
|
58
|
+
const items = e.clipboardData.items;
|
|
59
|
+
const files = [];
|
|
60
|
+
for (let i = 0; i < items.length; i++) {
|
|
61
|
+
if (items[i].kind === "file") files.push(items[i].getAsFile());
|
|
62
|
+
}
|
|
63
|
+
if (files.length > 0) this.handleFiles(files);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
handleFiles(files) {
|
|
68
|
+
const fileArray = Array.from(files).filter(file =>
|
|
69
|
+
this.options.allowedTypes.some(type => file.type.startsWith(type))
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
this.selectedFiles.push(...fileArray);
|
|
73
|
+
this.renderPreviews();
|
|
74
|
+
|
|
75
|
+
if (this.options.onFilesUpdate) {
|
|
76
|
+
this.options.onFilesUpdate(this.selectedFiles);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
removeFile(fileToRemove) {
|
|
81
|
+
this.selectedFiles = this.selectedFiles.filter(f => f !== fileToRemove);
|
|
82
|
+
this.renderPreviews();
|
|
83
|
+
if (this.options.onFilesUpdate) {
|
|
84
|
+
this.options.onFilesUpdate(this.selectedFiles);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
renderPreviews() {
|
|
89
|
+
this.previewContainer.innerHTML = "";
|
|
90
|
+
this.selectedFiles.forEach((file) => {
|
|
91
|
+
const reader = new FileReader();
|
|
92
|
+
reader.readAsDataURL(file);
|
|
93
|
+
reader.onloadend = () => {
|
|
94
|
+
const wrapper = document.createElement("div");
|
|
95
|
+
wrapper.className = "image-preview-wrapper";
|
|
96
|
+
wrapper.innerHTML = `
|
|
97
|
+
<img src="${reader.result}" alt="${file.name}">
|
|
98
|
+
<span class="remove-icon">×</span>
|
|
99
|
+
`;
|
|
100
|
+
wrapper.querySelector(".remove-icon").onclick = () => this.removeFile(file);
|
|
101
|
+
this.previewContainer.appendChild(wrapper);
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Helper to get current files from outside
|
|
107
|
+
getFiles() {
|
|
108
|
+
return this.selectedFiles;
|
|
109
|
+
}
|
|
110
|
+
}
|
package/src/styles.css
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
.upload-container {
|
|
2
|
+
width: 100%;
|
|
3
|
+
max-width: 500px;
|
|
4
|
+
min-height: 200px;
|
|
5
|
+
border: 2px dashed #ccc;
|
|
6
|
+
border-radius: 10px;
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
align-items: center;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
transition:
|
|
12
|
+
background 0.3s,
|
|
13
|
+
border-color 0.3s;
|
|
14
|
+
padding: 20px;
|
|
15
|
+
font-family: sans-serif;
|
|
16
|
+
position: relative; /* Context for children elements */
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* Make only the prompt text clickable, not the whole container */
|
|
20
|
+
#prompt-text {
|
|
21
|
+
cursor: pointer;
|
|
22
|
+
margin: 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.upload-container.drag-over {
|
|
26
|
+
background: #f0f8ff;
|
|
27
|
+
border-color: #007bff;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#preview-container {
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-wrap: wrap;
|
|
33
|
+
justify-content: center;
|
|
34
|
+
margin-top: 20px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Styling for the wrapper of each preview */
|
|
38
|
+
.image-preview-wrapper {
|
|
39
|
+
position: relative; /* Context for remove-icon positioning */
|
|
40
|
+
margin: 5px;
|
|
41
|
+
width: 80px;
|
|
42
|
+
height: 80px;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.image-preview-wrapper img {
|
|
46
|
+
width: 100%;
|
|
47
|
+
height: 100%;
|
|
48
|
+
object-fit: cover;
|
|
49
|
+
border-radius: 5px;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* The style for the cross icon */
|
|
53
|
+
.remove-icon {
|
|
54
|
+
position: absolute;
|
|
55
|
+
top: -8px; /* Slightly offset from the corner */
|
|
56
|
+
right: -8px;
|
|
57
|
+
cursor: pointer;
|
|
58
|
+
background: rgba(0, 0, 0, 0.6);
|
|
59
|
+
color: white;
|
|
60
|
+
padding: 3px 6px;
|
|
61
|
+
border-radius: 50%;
|
|
62
|
+
font-size: 14px;
|
|
63
|
+
font-weight: bold;
|
|
64
|
+
line-height: 1;
|
|
65
|
+
z-index: 10; /* Ensure it sits on top of everything */
|
|
66
|
+
transition: background 0.2s;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.remove-icon:hover {
|
|
70
|
+
background: rgba(255, 0, 0, 0.8); /* Turns red on hover */
|
|
71
|
+
}
|