Simplify the drag & drop API. Pass in a callback function, get drop events with a flat object of paths and files.
Inspired by feross/drag-drop -- drag & drop usable by humans.
npm i -S @substrate-system/drag-drop
This exposes ESM and common JS via the package.json exports
field.
import { dragDrop } from '@substrate-system/drag-drop'
const { dragDrop } = require('@substrate-system/drag-drop')
This package exposes minified JS files too. Copy them to a location that is accessible to your web server, then link to them in HTML.
cp ./node_modules/@substrate-system/drag-drop/dist/index.min.js ./public/drag-drop.min.js
<script type="module" src="./drag-drop.min.js"></script>
This exposes a single function, dragDrop
. Pass in a callback function, and get data objects containing all the files or directories that were dropped. By default the callback will not see any hidden files (dot files). Pass in another argument with { showHiddenFiles: true }
if you do want to see hidden files.
import { dragDrop, type DropRecord } from '@substrate-system/drag-drop'
// pass in an element or a CSS query selector
dragrop('.dropper', (drop:DropRecord, { pos, files }) => {
console.log('drop position', pos)
// => { x: 100, y: 200 }
// drop a folder or file
console.log('the dropped files', drop)
// we get the FileList object from the event too
console.log('the file list', files)
}, { showHiddenFiles: true }) // <-- third argument is optional
When someone hovers and drops something, a class .drag
is added to the drop target.
.drag {
border: 5px solid red;
}
A map from path name to file object.
type DropRecord = Record<string, File|Uint8Array>
{ '/abc/123': aFile }
type Listener = (dropped:DropRecord, opts:{
pos:{ x:number, y:number };
files:FileList;
})=>any
type ListenerObject = {
onDrop:Listener;
onDropText?:(text:string, pos:{ x, y })=>any;
onDragEnter?:(event:DragEvent)=>any;
onDragOver?:(event:DragEvent)=>any;
onDragLeave?:(event:DragEvent)=>any;
}
A single function, dragDrop
, that takes an element, a listener, an an options object.
The third argument has a property showHiddenFiles
, which if true
will callback with all files, including ones that start with .
. By default is false
.
function dragDrop (
elem:HTMLElement|string,
listeners:Listener|ListenerObject,
opts?:{ showHiddenFiles?:boolean }
):void
Drop a folder, get a flat object containing the files mapped by their path names.
Given a folder structure like this:
abc
├── aaaaa
│ └── bbb
│ └── testbbb.txt
└── test.txt
3 directories, 2 files
If we drop the top folder, abc
into the drop zone, then we get an object like this:
{
"/abc/aaaaa/bbb/testbbb.txt": File,
"/abc/test.txt": File
}
import { dragDrop, type DropRecord } from '@substrate-system/drag-drop'
dragDrop('.dropzone', (drop:DropRecord, { pos } => {
debug('the drop', drop)
// =>
// {
// "/abc/aaaaa/bbb/testbbb.txt": {},
// "/abc/test2.txt": {},
// "/abc/test.txt": {}
// }
}
Hidden files
Pass in an options object with { showHiddenFiles: true }
to get results including dot files. By default this will exclude hidden files from the results.
import { dragDrop } from '@substrate-system/drag-drop'
dragDrop('.dropzone', (dropRecord) => {
debug('including hidden files...', dropRecord)
// =>
// {
// "/abc/.DS_Store": {},
// "/abc/aaaaa/.DS_Store": {},
// "/abc/aaaaa/bbb/testbbb.txt": {},
// "/abc/test2.txt": {},
// "/abc/test.txt": {}
// }
}, { showHiddenFiles: true })
The returned object is a flat record with path names pointing at File
objects.
Drop a single file, get an object with just the one file:
{
"/test.txt": File
}
Do manual testing, because it is difficult to mock the drop events.
npm start