UNPKG

@uppy/drop-target

Version:

Lets your users drag and drop files on a DOM element

162 lines (156 loc) 5.59 kB
import { BasePlugin } from '@uppy/core'; import getDroppedFiles from '@uppy/utils/lib/getDroppedFiles'; import toArray from '@uppy/utils/lib/toArray'; // 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": "3.1.1" }; // Default options const defaultOpts = { target: null }; function isFileTransfer(event) { var _event$dataTransfer$t, _event$dataTransfer; return (_event$dataTransfer$t = (_event$dataTransfer = event.dataTransfer) == null || (_event$dataTransfer = _event$dataTransfer.types) == null ? void 0 : _event$dataTransfer.some(type => type === 'Files')) != null ? _event$dataTransfer$t : false; } /** * Drop Target plugin * */ export default class DropTarget extends BasePlugin { constructor(uppy, opts) { super(uppy, { ...defaultOpts, ...opts }); 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.handleDrop = async event => { var _event$currentTarget, _this$opts$onDrop, _this$opts; if (!isFileTransfer(event)) { return; } event.preventDefault(); event.stopPropagation() // Remove dragover class ; (_event$currentTarget = event.currentTarget) == null || _event$currentTarget.classList.remove('uppy-is-drag-over'); this.setPluginState({ isDraggingOver: false }); // Let any acquirer plugin (Url/Webcam/etc.) handle drops to the root this.uppy.iteratePlugins(plugin => { if (plugin.type === 'acquirer') { // @ts-expect-error Every Plugin with .type acquirer can define handleRootDrop(event) plugin.handleRootDrop == null || plugin.handleRootDrop(event); } }); // Add all dropped files, handle errors let executedDropErrorOnce = false; const logDropError = error => { this.uppy.log(error, 'error'); // In practice all drop errors are most likely the same, // so let's just show one to avoid overwhelming the user if (!executedDropErrorOnce) { this.uppy.info(error.message, 'error'); executedDropErrorOnce = true; } }; const files = await getDroppedFiles(event.dataTransfer, { logDropError }); if (files.length > 0) { this.uppy.log('[DropTarget] Files were dropped'); this.addFiles(files); } (_this$opts$onDrop = (_this$opts = this.opts).onDrop) == null || _this$opts$onDrop.call(_this$opts, event); }; this.handleDragOver = event => { var _this$opts$onDragOver, _this$opts2; if (!isFileTransfer(event)) { return; } event.preventDefault(); event.stopPropagation(); // 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) event.dataTransfer.dropEffect = 'copy' // eslint-disable-line no-param-reassign ; event.currentTarget.classList.add('uppy-is-drag-over'); this.setPluginState({ isDraggingOver: true }); (_this$opts$onDragOver = (_this$opts2 = this.opts).onDragOver) == null || _this$opts$onDragOver.call(_this$opts2, event); }; this.handleDragLeave = event => { var _event$currentTarget2, _this$opts$onDragLeav, _this$opts3; if (!isFileTransfer(event)) { return; } event.preventDefault(); event.stopPropagation(); this.setPluginState({ isDraggingOver: false }); (_event$currentTarget2 = event.currentTarget) == null || _event$currentTarget2.classList.remove('uppy-is-drag-over'); (_this$opts$onDragLeav = (_this$opts3 = this.opts).onDragLeave) == null || _this$opts$onDragLeav.call(_this$opts3, event); }; this.addListeners = () => { const { target } = this.opts; if (target instanceof Element) { this.nodes = [target]; } else if (typeof target === 'string') { this.nodes = toArray(document.querySelectorAll(target)); } if (!this.nodes || this.nodes.length === 0) { throw new Error(`"${target}" does not match any HTML elements`); } this.nodes.forEach(node => { node.addEventListener('dragover', this.handleDragOver, false); node.addEventListener('dragleave', this.handleDragLeave, false); node.addEventListener('drop', this.handleDrop, false); }); }; this.removeListeners = () => { if (this.nodes) { this.nodes.forEach(node => { node.removeEventListener('dragover', this.handleDragOver, false); node.removeEventListener('dragleave', this.handleDragLeave, false); node.removeEventListener('drop', this.handleDrop, false); }); } }; this.type = 'acquirer'; this.id = this.opts.id || 'DropTarget'; } install() { this.setPluginState({ isDraggingOver: false }); this.addListeners(); } uninstall() { this.removeListeners(); } } DropTarget.VERSION = packageJson.version;