@uppy/drag-drop
Version:
Droppable zone UI for Uppy. Drag and drop files into it to upload.
209 lines (203 loc) • 6.35 kB
JavaScript
import { UIPlugin } from '@uppy/core';
import toArray from '@uppy/utils/lib/toArray';
import isDragDropSupported from '@uppy/utils/lib/isDragDropSupported';
import getDroppedFiles from '@uppy/utils/lib/getDroppedFiles';
import { h } from 'preact';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore We don't want TS to generate types for the package.json
const packageJson = {
"version": "4.1.1"
};
import locale from './locale.js';
const defaultOptions = {
inputName: 'files[]',
width: '100%',
height: '100%'
};
/**
* Drag & Drop plugin
*
*/
export default class DragDrop extends UIPlugin {
constructor(uppy, opts) {
super(uppy, {
...defaultOptions,
...opts
});
// Check for browser dragDrop support
this.isDragDropSupported = isDragDropSupported();
this.addFiles = files => {
const descriptors = files.map(file => ({
source: this.id,
name: file.name,
type: file.type,
data: file,
meta: {
// path of the file relative to the ancestor directory the user selected.
// e.g. 'docs/Old Prague/airbnb.pdf'
relativePath: file.relativePath || null
}
}));
try {
this.uppy.addFiles(descriptors);
} catch (err) {
this.uppy.log(err);
}
};
this.onInputChange = event => {
const files = toArray(event.currentTarget.files || []);
if (files.length > 0) {
this.uppy.log('[DragDrop] Files selected through input');
this.addFiles(files);
}
// Clear the input so that Chrome can detect file section when the same file is repeatedly selected
// (see https://github.com/transloadit/uppy/issues/768#issuecomment-2264902758)
// eslint-disable-next-line no-param-reassign
event.currentTarget.value = '';
};
this.handleDragOver = event => {
var _this$opts$onDragOver, _this$opts;
event.preventDefault();
event.stopPropagation();
// Check if the "type" of the datatransfer object includes files. If not, deny drop.
const {
types
} = event.dataTransfer;
const hasFiles = types.some(type => type === 'Files');
const {
allowNewUpload
} = this.uppy.getState();
if (!hasFiles || !allowNewUpload) {
// eslint-disable-next-line no-param-reassign
event.dataTransfer.dropEffect = 'none';
return;
}
// Add a small (+) icon on drop
// (and prevent browsers from interpreting this as files being _moved_ into the browser
// https://github.com/transloadit/uppy/issues/1978)
//
// eslint-disable-next-line no-param-reassign
event.dataTransfer.dropEffect = 'copy';
this.setPluginState({
isDraggingOver: true
});
(_this$opts$onDragOver = (_this$opts = this.opts).onDragOver) == null || _this$opts$onDragOver.call(_this$opts, event);
};
this.handleDragLeave = event => {
var _this$opts$onDragLeav, _this$opts2;
event.preventDefault();
event.stopPropagation();
this.setPluginState({
isDraggingOver: false
});
(_this$opts$onDragLeav = (_this$opts2 = this.opts).onDragLeave) == null || _this$opts$onDragLeav.call(_this$opts2, event);
};
this.handleDrop = async event => {
var _this$opts$onDrop, _this$opts3;
event.preventDefault();
event.stopPropagation();
this.setPluginState({
isDraggingOver: false
});
const logDropError = error => {
this.uppy.log(error, 'error');
};
// Add all dropped files
const files = await getDroppedFiles(event.dataTransfer, {
logDropError
});
if (files.length > 0) {
this.uppy.log('[DragDrop] Files dropped');
this.addFiles(files);
}
(_this$opts$onDrop = (_this$opts3 = this.opts).onDrop) == null || _this$opts$onDrop.call(_this$opts3, event);
};
this.type = 'acquirer';
this.id = this.opts.id || 'DragDrop';
this.title = 'Drag & Drop';
this.defaultLocale = locale;
this.i18nInit();
}
renderHiddenFileInput() {
var _restrictions$allowed;
const {
restrictions
} = this.uppy.opts;
return h("input", {
className: "uppy-DragDrop-input",
type: "file",
hidden: true,
ref: ref => {
this.fileInputRef = ref;
},
name: this.opts.inputName,
multiple: restrictions.maxNumberOfFiles !== 1,
accept: (_restrictions$allowed = restrictions.allowedFileTypes) == null ? void 0 : _restrictions$allowed.join(', '),
onChange: this.onInputChange
});
}
static renderArrowSvg() {
return h("svg", {
"aria-hidden": "true",
focusable: "false",
className: "uppy-c-icon uppy-DragDrop-arrow",
width: "16",
height: "16",
viewBox: "0 0 16 16"
}, h("path", {
d: "M11 10V0H5v10H2l6 6 6-6h-3zm0 0",
fillRule: "evenodd"
}));
}
renderLabel() {
return h("div", {
className: "uppy-DragDrop-label"
}, this.i18nArray('dropHereOr', {
browse: h("span", {
className: "uppy-DragDrop-browse"
}, this.i18n('browse'))
}));
}
renderNote() {
return h("span", {
className: "uppy-DragDrop-note"
}, this.opts.note);
}
render() {
const dragDropClass = `uppy-u-reset
uppy-DragDrop-container
${this.isDragDropSupported ? 'uppy-DragDrop--isDragDropSupported' : ''}
${this.getPluginState().isDraggingOver ? 'uppy-DragDrop--isDraggingOver' : ''}
`;
const dragDropStyle = {
width: this.opts.width,
height: this.opts.height
};
return h("button", {
type: "button",
className: dragDropClass,
style: dragDropStyle,
onClick: () => this.fileInputRef.click(),
onDragOver: this.handleDragOver,
onDragLeave: this.handleDragLeave,
onDrop: this.handleDrop
}, this.renderHiddenFileInput(), h("div", {
className: "uppy-DragDrop-inner"
}, DragDrop.renderArrowSvg(), this.renderLabel(), this.renderNote()));
}
install() {
const {
target
} = this.opts;
this.setPluginState({
isDraggingOver: false
});
if (target) {
this.mount(target, this);
}
}
uninstall() {
this.unmount();
}
}
DragDrop.VERSION = packageJson.version;