UNPKG

@uppy/drag-drop

Version:

Droppable zone UI for Uppy. Drag and drop files into it to upload.

209 lines (203 loc) 6.35 kB
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;