GithubHelp home page GithubHelp logo

chanced / filedrop-svelte Goto Github PK

View Code? Open in Web Editor NEW
108.0 3.0 12.0 359 KB

File dropzone for Svelte.

License: MIT License

JavaScript 2.26% TypeScript 72.67% HTML 0.71% Svelte 24.36%
dropzone file svelte drag-and-drop

filedrop-svelte's Introduction

FileDrop

A file dropzone action & component for Svelte.

Install

npm i filedrop-svelte -D

# yarn add filedrop-svelte -dev

If using Typescript, see the Typescript section.

Usage

filedrop-svelte comes with both a component and an action. The component is basically a wrapper around the action with some some default styling.

Component

See this REPL for minmimal usage.

<script>
	import FileDrop from "filedrop-svelte";
	import type { Files } from "filedrop-svelte";
	import fileSize from "filesize";
	let files: Files;
</script>

<FileDrop on:filedrop={(e) => { files = e.detail.files }}>
        Upload files
</FileDrop>

{#if files}
	<h3>Accepted files</h3>
	<ul>
		{#each files.accepted as file}
			<li>{file.name} - {fileSize(file.size)}</li>
		{/each}
	</ul>
	<h3>Rejected files</h3>
	<ul>
		{#each files.rejected as rejected}
			<li>{rejected.file.name} - {rejected.error.message}</li>
		{/each}
	</ul>
{/if}

Action

See this REPL for minimal usage.

<script>
	import { filedrop } from "filedrop-svelte";
	import type { Files, FileDropOptions } from "filedrop-svelte";
	let options: FileDropOptions = {};
	let files: Files;
</script>

<div use:filedrop={options} on:filedrop={(e) => {files = e.detail.files}}>
	<!-- you can add your input[type="file"] here if you want.
	or you can omit it and it'll be appended -->
	Drag &amp; drop files
	{files}
</div>

Reference

Options

parameter purpose type default
accept specify file types to accept. See HTML attribute: accept on MDN Web Docs for more information. string string[] undefined
maxSize the maximum size a file can be in bytes. number undefined
minSize the minimum size a file can be in bytes. number undefined
fileLimit total number of files allowed in a transaction. A value of 0 disables the action/component, 1 turns multiple off, and any other value enables multiple. Any attempt to upload more files than allowed will result in the files being placed in rejections numer undefined
multiple sets the file input to multiple. See HTML attribute: multiple on MDN Web Docs for more information. boolean true
disabled disables the action/component, removing all event listeners boolean false
windowDrop determines whether or not files can be dropped anywhere in the window. A value of false would require that the files be droppped within the <FileDrop> component or the element with use:filedrop. boolean true
clickToUpload causes the containing element to be treated as the input. If hideInput is true or undefined, disabling this does not change the tabindex of the container or remove the keydown eventListener boolean true
tabIndex tab index of the container. if disabled is true then this is set to -1. If clickToUpload is true or undefined, this defaults to 0. number 0
hideInput if true or undefined, input[type='file'] will be set to display:none boolean true
input allows you to explicitly pass a reference to the file HTMLInputElement as a parameter. If undefined, the action will search for input[type="file"]. If one is not found, it will be appeneded to the element with use:filedrop HTMLInputElement undefined

Events

event description event.detail
filedrop one or more files has been selected in the file dialog or drag-and-dropped FileDropSelectEvent
filedragenter a dragenter event has occurred on the container element containnig one or more files FileDropDragEvent
filedragleave a dragleave event has occurred on the container element containing one or more files FileDropDragEvent
filedragover a dragover event has occurred on the container element containing one or more files FileDropDragEvent
filedialogcancel the file dialog has been canceled without selecting files FileDropEvent
filedialogclose the file dialog has been closed with files selected FileDropEvent
filedialogopen the file dialog has been opened FileDropEvent
windowfiledragenter a dragenter event has occurred on the document (event is named windowfiledragenter so not to confuse document with file) FileDropDragEvent
windowfiledragleave a dragleave event has occurred on the document (event is named windowfiledragleave so not to confuse document with file) FileDropDragEvent
windowfiledragover a dragover event has occurred on the document (event is named windowfiledragover so not to confuse document with file) FileDropDragEvent

Errors

class reason code
InvalidFileTypeError file type does not satisfy accept InvalidFileType (0)
FileCountExceededError total number of files selected or dropped exceeds fileLimit FileCountExceeded (1)
FileSizeMinimumNotMetError file does not satisify minSize FileSizeMinimumNotMet (2)
FileSizeMaximumExceededError file does not satisify maxSize FileSizeMaximumExceeded (3)

Typescript

In order for typings to work properly, you'll need to add the following to global.d.ts until this issue is resolved:

declare type FileDropEvent = import("filedrop-svelte/event").FileDropEvent;
declare type FileDropSelectEvent = import("filedrop-svelte/event").FileDropSelectEvent;
declare type FileDropDragEvent = import("filedrop-svelte/event").FileDropDragEvent;
declare namespace svelte.JSX {
    interface HTMLAttributes<T> {
        onfiledrop?: (event: CustomEvent<FileDropSelectEvent> & { target: EventTarget & T }) => void;
        onfiledragenter?: (event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }) => void;
        onfiledragleave?: (event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }) => void;
        onfiledragover?: (event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }) => void;
        onfiledialogcancel?: (event: CustomEvent<FileDropEvent> & { target: EventTarget & T }) => void;
        onfiledialogclose?: (event: CustomEvent<FileDropEvent> & { target: EventTarget & T }) => void;
        onfiledialogopen?: (event: CustomEvent<FileDropEvent> & { target: EventTarget & T }) => void;
        onwindowfiledragenter?: (event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }) => void;
        onwindowfiledragleave?: (event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }) => void;
        onwindowfiledragover?: (event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }) => void;
    }
}

You may need to edit tsconfig.json to include global.d.ts if it isn't already.

Alternatives

Previous art

Dependencies

Todo

  • tests
  • better documentation
  • demo website

License

MIT

filedrop-svelte's People

Contributors

chanced avatar mentalgear avatar n0texisting avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

filedrop-svelte's Issues

options.multiple appears to incorrectly set fileLimit to 1

I'd expect leaving options.multiple as the default & setting options.fileLimit to anything > 1 to allow multiple files to be uploaded.

Is the a ! missing from this code ?

export function processFiles(files: FileWithPath[], options: FileDropOptions): Files {
	let { fileLimit } = options;
	if (options.multiple) {
		fileLimit = 1;
	}

If not, then what options do I set to upload multiple files ?

Add filedragover event to FileDrop Action Example

It would be nice for the FileDrop Action Example to visually indicate the filedragover event. Maybe by changing border or background color.

This would be especially useful if you have multiple FileDrop elements and windowDrop=false. With the visual indication the user knows for sure that s/he is dropping the file on an active element (and not just next to it).

I tried to create a FileDrop Action Example with visual filedragenter but the filedragover event is lost when the file is moved over the cloud image or text within the FileDrop element.

Native support for directory uploads using the system dialog

Hi there,

I just found your library and it serves my purpose pretty well! If I may, I would like to suggest that you add support for directory uploads using the system dialog via the webkitdirectory (caniuse.com) property. This way, folder uploads can be supported when uploading via the system dialog.

I am not quite sure how to do this currently, as using use:filedrop allows me to specifiy my own input[type="file"], but these elements are automatically hidden. This prevents me from showing two upload buttons instead of one ("upload files", "upload folder"), which is exactly what Google does with Google Drive.

See screenshot

I would love to hear your thoughts on this!

Component Height is Hardcoded

Currently the component height is hardcoded at 200px which is anoying as it is way to high for my purposes and might be to small for other people.

I've made a PR (#3)

Incorrect error code thrown with FileSizeLimitExceededError

Hi!

I found that FileSizeLimitExceededError exception contains incorrect ErrorCode - FileSizeMinimumNotMet instead of FileSizeMaximumExceeded

Please, check it out:

export class FileSizeLimitExceededError extends FileDropError {
limit: number;
readableLimit: string;
readableSize: string;
constructor(file: File, limit: number, message?: string) {
message = message ?? `file size ${file.size} exceeds file size limit of ${limit}.`;
super(ErrorCode.FileSizeMinimumNotMet, file, message);
}
}

filedragenter/filedragleave are both emitted whilst in the drop zone

First mentioned here: #5
From what I can understand from the docs, I think filedragenter and filedragleave are emitted too often.

I assume that filedragenter should only be emitted once, when the user's cursor enters the dropzone while dragging some files. The reverse should be true for filedragleave.

In this REPL (fixed), you can observe the console logs by opening your DevTools. If you drag some files to the drop zone (don't release) and start moving your mouse up and down inside the drop zone, events are emitted (both enter and leave events).

Where do the files go

I know this might be a silly question but I am new to svelte and have spent about an hour trying to figure out where the files save too and I have not figured it out so I though it would be worth a shot to ask here

No way to disable the keydown-listener (space / enter key)

Problem
The current configuration options do not allow disabling the keydown listener for the space and enter key. The only way to achieve this so far is to set the dropzone to disabled, which for obvious reasons does not lead to the desired result.
Proposed Solution
Therefore, I suggest adding a configuration option called "spaceToUpload" / "enterToUpload" / "keyDownToUpload" which can be set to false.

Edit: After digging through the code, I found an undocumented way to remove the keydown listener: hideInput and clickToUpload must both be set to false.

Export types

Many thanks for this great module!

However, I came across some type issues.
If I use
declare type FileDropEvent = import("filedrop-svelte/lib/event").FileDropEvent;
it doesn't work because "filedrop-svelte/lib/event" doesn't exist as it's not exported.

Typescript Declaration needs updating for Svelte 4

svelte-check will throw an error at the moment if you try to use events with dom elements with Svelte 4, I think the typescript declaration now needs to look more like this:

declare type FileDropEvent = import('filedrop-svelte/event').FileDropEvent;
declare type FileDropSelectEvent = import('filedrop-svelte/event').FileDropSelectEvent;
declare type FileDropDragEvent = import('filedrop-svelte/event').FileDropDragEvent;
declare namespace svelteHTML {
  interface HTMLAttributes<T> {
      'on:filedrop'?: (
          event: CustomEvent<FileDropSelectEvent> & {
              target: EventTarget & T;
          }
      ) => void;
      // etc
  }
}

(svelteHTML namespace instead of 'svelte.JSX' and 'on:event' instead of 'onevent', this seems to work for me)

FR: Clipboard Support

Support files that are pasted -- even just an example in the documentation if that is more appropriate.

Thanks!

How to use windowDrop with Component?

I want to use multiple FileDrops, therefore disable windowDrop.

I expected

<FileDrop windowDrop="false" on:filedrop={(e) => { files = e.detail.files }}>
        Upload files
</FileDrop>

but I get a TypeScript error. How can I pass the additional option?

Uploading same file via click fails

When using the "click to upload" feature, the on:filedrop event doesn't fire when you attempt to upload the same file a second time. This appears to be a fairly well-known behavior of the <input type="file"> component:

Repro case should be something like the following:

// my-test.svelte
<script>
  function onDrop(event:CustomEvent) {
    console.info("dropped", event)
  }
</script>
<div 
    use:filedrop={{ clickToUpload: true }} 
    on:filedrop={onDrop}
/>

Run the above then:

  • click on the dropzone and select a file -- notice that the console message is printed.
  • click on dropzone again and select the same file -- notice that the console message is not printed this time.
  • click on dropzone and select a different file -- notice that the message is printed

In my app, I have added a timeout to my onDrop() which clears the field between clicks, which fixes the problem.
I'm sure there is a more elegant solution.

onDrop(event:CustomEvent) {
    console.info("dropped", event)
    const input = (event.target as HTMLElement)?.querySelector?.("input") as HTMLInputElement
    if (input) {
      setTimeout(() => {
        try {
          input.value = ""
        } catch (e) {}
      }, 100)
    }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.