master cedd55fd2ad0 cached
44 files
38.9 KB
11.3k tokens
17 symbols
1 requests
Download .txt
Repository: thecodejack/svelte-file-dropzone
Branch: master
Commit: cedd55fd2ad0
Files: 44
Total size: 38.9 KB

Directory structure:
gitextract_nknodkyk/

├── .gitignore
├── .prettierrc
├── .storybook/
│   ├── main.js
│   └── preview-head.html
├── README.md
├── TODO
├── demo/
│   ├── .gitignore
│   ├── .npmrc
│   ├── .prettierignore
│   ├── .prettierrc
│   ├── README.md
│   ├── package.json
│   ├── src/
│   │   ├── app.d.ts
│   │   ├── app.html
│   │   ├── index.test.ts
│   │   ├── lib/
│   │   │   └── index.ts
│   │   └── routes/
│   │       ├── basic/
│   │       │   └── +page.svelte
│   │       ├── custom-props/
│   │       │   └── +page.svelte
│   │       ├── form/
│   │       │   ├── +page.server.ts
│   │       │   └── +page.svelte
│   │       ├── reactive-disabled/
│   │       │   └── +page.svelte
│   │       └── toggle-multiple/
│   │           └── +page.svelte
│   ├── svelte.config.js
│   ├── tsconfig.json
│   └── vite.config.ts
├── jsconfig.json
├── package.json
├── renovate.json
├── rollup.config.js
├── src/
│   └── lib/
│       ├── components/
│       │   └── Dropzone.svelte
│       ├── index.ts
│       └── utils/
│           ├── attr-accept.js
│           └── index.js
└── stories/
    ├── 1-dropzone.stories.js
    ├── 2-advanced-dropzone.stories.js
    ├── helpers.js
    └── views/
        ├── BasicDropzoneAcceptImagesView.svelte
        ├── BasicDropzoneView.svelte
        ├── CustomSlotDropzoneView.svelte
        ├── DisabledDropzoneView.svelte
        ├── FullyFeaturedDropzoneView.svelte
        ├── NoClickDropzoneView.svelte
        ├── NoDragDropzoneView.svelte
        └── WorkingCSVFileUploadView.svelte

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
node_modules
dist
storybook-static
package-lock.json
.DS_Store
.svelte-kit


================================================
FILE: .prettierrc
================================================
{
	"useTabs": false,
	"singleQuote": false,
	"trailingComma": "none",
	"printWidth": 100,
	"plugins": ["prettier-plugin-svelte"],
	"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }],
	"arrowParens": "avoid"
}



================================================
FILE: .storybook/main.js
================================================
export default {
  stories: ["../stories/**/*.stories.js"],
  addons: ["@storybook/addon-links", "@storybook/addon-essentials", "@storybook/addon-interactions"],
  framework: {
    name: "@storybook/sveltekit",
    options: {},
  },
  docs: {
    autodocs: true,
  },
};


================================================
FILE: .storybook/preview-head.html
================================================
<script>
  window.global = window;
</script>


================================================
FILE: README.md
================================================
# svelte-file-dropzone

[![NPM](https://img.shields.io/npm/v/svelte-file-dropzone.svg)](https://www.npmjs.com/package/svelte-file-dropzone)
[![npm bundle size (minified + gzip)](https://img.shields.io/bundlephobia/minzip/svelte-file-dropzone.svg)](https://www.npmjs.com/package/svelte-file-dropzone)

SvelteJS component for file upload and dropzone.The component is Svelte implementation of [react-dropzone](https://github.com/react-dropzone/react-dropzone).

## Demo

[Click here for Storybook link](https://svelte-file-dropzone.netlify.app/?path=/info/examples--basic-dropzone)

## Installation

```
npm install svelte-file-dropzone

or

yarn add svelte-file-dropzone
```

## Usage

```svelte
<script>
  import Dropzone from "svelte-file-dropzone";

  let files = {
    accepted: [],
    rejected: []
  };

  function handleFilesSelect(e) {
    const { acceptedFiles, fileRejections } = e.detail;
    files.accepted = [...files.accepted, ...acceptedFiles];
    files.rejected = [...files.rejected, ...fileRejections];
  }
</script>

<Dropzone on:drop={handleFilesSelect} />
<ol>
  {#each files.accepted as item}
    <li>{item.name}</li>
  {/each}
</ol>
```

## API

### Props

| Prop Name             | Description                                                                              | Default Value |
| --------------------- | ---------------------------------------------------------------------------------------- | ------------- |
| accept                | Set accepted file types. See https://github.com/okonet/attr-accept for more information. | undefined     |
| disabled              |                                                                                          | false         |
| maxSize               |                                                                                          | Infinity      |
| minSize               |                                                                                          | 0             |
| multiple              | if true, multiple files can be selected at once                                          | true          |
| preventDropOnDocument | 1231                                                                                     | true          |
| noClick               | disable click events                                                                     | false         |
| noKeyboard            | disable keyboard events                                                                  | false         |
| noDrag                | disable drag events                                                                      | false         |
| containerClasses      | custom container classes                                                                 | ""            |
| containerStyles       | custom inline container styles                                                           | ""            |
| disableDefaultStyles  | don't apply default styles to container                                                  | false         |
| inputElement          | reference to inputElement                                                                | undefined     |
| required              | html5 required attribute added to input                                                  | false         |

### Events

| Event Name       | Description | `event.detail` info                    |
| ---------------- | ----------- | -------------------------------------- |
| dragenter        |             | `{dragEvent: event}`                   |
| dragover         |             | `{dragEvent: event}`                   |
| dragleave        |             | `{dragEvent: event}`                   |
| drop             |             | `{acceptedFiles,fileRejections,event}` |
| filedropped      |             | `{event}`                              |
| droprejected     |             | `{fileRejections,event}`               |
| dropaccepted     |             | `{acceptedFiles,event}`                |
| filedialogcancel |             |                                        |

### Examples

[Click here](https://github.com/thecodejack/svelte-file-dropzone/tree/master/stories/views) to view stories implementation

## Credits

Component is reimplementation [react-dropzone](https://github.com/react-dropzone/react-dropzone). Complete credit goes to author and contributors of [react-dropzone](https://github.com/react-dropzone/react-dropzone).

## License

MIT


================================================
FILE: TODO
================================================

Todo:
  ✔ Git repo @done(20-06-17 21:58)
  ✔ npm initial publish @done(20-06-18 22:34)
  ✔ setup netlify @done(20-06-17 22:55)
  ✔ Fix README.md @done(20-06-17 22:28)
  ✔ Add README.md to Notes of storybook @done(20-06-18 22:34)
  ✔ Build setup @done(20-06-17 22:33)
  ☐ Advanced Examples
    ☐ Custom Dropzone with delete file etc
    ✔ CustomDropzone with different drop behaviour @done(20-06-18 22:34)
    


================================================
FILE: demo/.gitignore
================================================
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*


================================================
FILE: demo/.npmrc
================================================
engine-strict=true


================================================
FILE: demo/.prettierignore
================================================
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock


================================================
FILE: demo/.prettierrc
================================================
{
	"useTabs": true,
	"singleQuote": true,
	"trailingComma": "none",
	"printWidth": 100,
	"plugins": ["prettier-plugin-svelte"],
	"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}


================================================
FILE: demo/README.md
================================================
# create-svelte

Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).

## Creating a project

If you're seeing this, you've probably already done this step. Congrats!

```bash
# create a new project in the current directory
npm create svelte@latest

# create a new project in my-app
npm create svelte@latest my-app
```

## Developing

Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:

```bash
npm run dev

# or start the server and open the app in a new browser tab
npm run dev -- --open
```

## Building

To create a production version of your app:

```bash
npm run build
```

You can preview the production build with `npm run preview`.

> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.


================================================
FILE: demo/package.json
================================================
{
	"name": "demo",
	"version": "0.0.1",
	"private": true,
	"scripts": {
		"dev": "vite dev",
		"build": "vite build",
		"preview": "vite preview",
		"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
		"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
		"test": "vitest",
		"lint": "prettier --check .",
		"format": "prettier --write ."
	},
	"devDependencies": {
		"@sveltejs/adapter-auto": "^3.0.0",
		"@sveltejs/kit": "^2.5.5",
		"@sveltejs/vite-plugin-svelte": "^3.0.0",
		"prettier": "^3.1.1",
		"prettier-plugin-svelte": "^3.1.2",
		"svelte": "^4.2.12",
		"svelte-check": "^3.6.0",
		"tslib": "^2.4.1",
		"typescript": "^5.0.0",
		"vite": "^5.0.3",
		"vitest": "^1.0.0"
	},
	"type": "module"
}


================================================
FILE: demo/src/app.d.ts
================================================
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
declare global {
	namespace App {
		// interface Error {}
		// interface Locals {}
		// interface PageData {}
		// interface PageState {}
		// interface Platform {}
	}
}

export {};


================================================
FILE: demo/src/app.html
================================================
<!doctype html>
<html lang="en">
	<head>
		<meta charset="utf-8" />
		<link rel="icon" href="%sveltekit.assets%/favicon.png" />
		<meta name="viewport" content="width=device-width, initial-scale=1" />
		%sveltekit.head%
	</head>
	<body data-sveltekit-preload-data="hover">
		<div style="display: contents">%sveltekit.body%</div>
	</body>
</html>


================================================
FILE: demo/src/index.test.ts
================================================
import { describe, it, expect } from 'vitest';

describe('sum test', () => {
	it('adds 1 + 2 to equal 3', () => {
		expect(1 + 2).toBe(3);
	});
});


================================================
FILE: demo/src/lib/index.ts
================================================
// place files you want to import through the `$lib` alias in this folder.


================================================
FILE: demo/src/routes/basic/+page.svelte
================================================
<script lang="ts">
	import Dropzone from '../../../../src/lib/components/Dropzone.svelte';

	let files = {
		accepted: [] as any[],
		rejected: [] as any[]
	};

	function handleFilesSelect(e: any) {
		const { acceptedFiles, fileRejections } = e.detail;
		files.accepted = [...files.accepted, ...acceptedFiles];
		files.rejected = [...files.rejected, ...fileRejections];
	}
</script>

<section>
	<Dropzone on:drop={handleFilesSelect} />

	<ol>
		{#each files.accepted as item}
			<li>{item.name}</li>
		{/each}
	</ol>
</section>

<style>
	section {
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;
		flex: 1;
	}
</style>


================================================
FILE: demo/src/routes/custom-props/+page.svelte
================================================
<script lang="ts">
	import Dropzone from '../../../../src/lib/components/Dropzone.svelte';

	let files = {
		accepted: [] as any[],
		rejected: [] as any[]
	};

	function handleFilesSelect(e: any) {
		const { acceptedFiles, fileRejections } = e.detail;
		files.accepted = [...files.accepted, ...acceptedFiles];
		files.rejected = [...files.rejected, ...fileRejections];
	}

	function clickToUpload() {
		document.getElementById('xyz')!.click();
	}
</script>

<section>
	<button on:click={clickToUpload}>Click to upload</button>
	<Dropzone on:drop={handleFilesSelect} id="xyz" />

	<ol>
		{#each files.accepted as item}
			<li>{item.name}</li>
		{/each}
	</ol>
</section>

<style>
	section {
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;
		flex: 1;
	}
</style>


================================================
FILE: demo/src/routes/form/+page.server.ts
================================================
export const actions = {
	async postFiles({ request }) {
		const formData: FormData = await request.formData();
		const files = formData.getAll('files');

		return { files: files.map((f) => (f as any).name) };
	}
};


================================================
FILE: demo/src/routes/form/+page.svelte
================================================
<script lang="ts">
	import { enhance } from '$app/forms';
	import { page } from '$app/stores';
	import Dropzone from '../../../../src/lib/components/Dropzone.svelte';

	let files: { name: string }[] = [];

	function handleFilesSelect(e: any) {
		const { acceptedFiles } = e.detail;
		files = [...acceptedFiles];
	}
</script>

<form method="POST" action="?/postFiles" use:enhance enctype="multipart/form-data">
	<Dropzone on:drop={handleFilesSelect} name="files" />

	<button>Go</button>
</form>

Files about to upload:
<ul>
	{#each files as file}
		<li>{file.name}</li>
	{/each}
</ul>

<hr />

Files posted to form action:
<ul>
	{#each $page.form?.files ?? [] as file}
		<li>{file}</li>
	{/each}
</ul>


================================================
FILE: demo/src/routes/reactive-disabled/+page.svelte
================================================
<script lang="ts">
	import Dropzone from '../../../../src/lib/components/Dropzone.svelte';

	let files = {
		accepted: [] as any[],
		rejected: [] as any[]
	};

	function handleFilesSelect(e: any) {
		const { acceptedFiles, fileRejections } = e.detail;
		files.accepted = [...files.accepted, ...acceptedFiles];
		files.rejected = [...files.rejected, ...fileRejections];
	}

	let disabled = false;
	$: dropAddedStyles = disabled
		? 'border-color: lightgray; cursor: not-allowed;'
		: 'border-color: blue';
</script>

<section>
	<label>Disable dropzone <input type="checkbox" bind:checked={disabled} /></label>
	<Dropzone {disabled} on:drop={handleFilesSelect} containerStyles={dropAddedStyles} />

	<ol>
		{#each files.accepted as item}
			<li>{item.name}</li>
		{/each}
	</ol>
</section>

<style>
	section {
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;
		flex: 1;
	}
</style>


================================================
FILE: demo/src/routes/toggle-multiple/+page.svelte
================================================
<script lang="ts">
	import Dropzone from '../../../../src/lib/components/Dropzone.svelte';

	let files = {
		accepted: [] as any[],
		rejected: [] as any[]
	};

	function handleFilesSelect(e: any) {
		const { acceptedFiles, fileRejections } = e.detail;
		files.accepted = [...files.accepted, ...acceptedFiles];
		files.rejected = [...files.rejected, ...fileRejections];
	}

	let multiple = false;
</script>

<section>
	<label>Multiple <input type="checkbox" bind:checked={multiple} /></label>
	<Dropzone on:drop={handleFilesSelect} {multiple} />

	<ol>
		{#each files.accepted as item}
			<li>{item.name}</li>
		{/each}
	</ol>
</section>

<style>
	section {
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;
		flex: 1;
	}
</style>


================================================
FILE: demo/svelte.config.js
================================================
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';

/** @type {import('@sveltejs/kit').Config} */
const config = {
	// Consult https://kit.svelte.dev/docs/integrations#preprocessors
	// for more information about preprocessors
	preprocess: vitePreprocess(),

	kit: {
		// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
		// If your environment is not supported or you settled on a specific environment, switch out the adapter.
		// See https://kit.svelte.dev/docs/adapters for more information about adapters.
		adapter: adapter()
	}
};

export default config;


================================================
FILE: demo/tsconfig.json
================================================
{
	"extends": "./.svelte-kit/tsconfig.json",
	"compilerOptions": {
		"allowJs": true,
		"checkJs": true,
		"esModuleInterop": true,
		"forceConsistentCasingInFileNames": true,
		"resolveJsonModule": true,
		"skipLibCheck": true,
		"sourceMap": true,
		"strict": true,
		"moduleResolution": "bundler"
	}
	// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
	//
	// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
	// from the referenced tsconfig.json - TypeScript does not merge them in
}


================================================
FILE: demo/vite.config.ts
================================================
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vitest/config';

export default defineConfig({
	plugins: [sveltekit()],
	test: {
		include: ['src/**/*.{test,spec}.{js,ts}']
	}
});


================================================
FILE: jsconfig.json
================================================
{}


================================================
FILE: package.json
================================================
{
  "name": "svelte-file-dropzone",
  "version": "2.0.9",
  "description": "Svelte component for fileupload and file dropzone",
  "scripts": {
    "package": "svelte-kit sync && svelte-package && publint",
    "prepublishOnly": "npm run package",
    "test": "echo \"Error: no test specified\" && exit 1",
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build"
  },
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "svelte": "./dist/index.js"
    }
  },
  "typesVersions": {
    ">4.0": {
      "Dropzone.svelte": [
        "./dist/components/Dropzone.svelte.d.ts"
      ]
    }
  },
  "repository": {
    "url": "https://github.com/thecodejack/svelte-file-dropzone"
  },
  "author": "thecodejack",
  "license": "MIT",
  "dependencies": {
    "file-selector": "^0.6.0"
  },
  "peerDependencies": {
    "svelte": "^3.54.0 || ^4.0.0 || ^5"
  },
  "devDependencies": {
    "@storybook/addon-essentials": "^7.6.6",
    "@storybook/addon-interactions": "^7.6.6",
    "@storybook/addon-links": "^7.6.6",
    "@storybook/addons": "7.6.6",
    "@storybook/svelte": "7.6.6",
    "@storybook/sveltekit": "^7.6.6",
    "@sveltejs/kit": "^1.30.4",
    "@sveltejs/package": "^2.2.5",
    "babel-loader": "9.1.3",
    "publint": "^0.2.7",
    "storybook": "^7.6.6",
    "svelte": "^4.2.12",
    "vite": "^4.5.1"
  },
  "keywords": [
    "svelte",
    "svelte3",
    "svelte-components",
    "upload",
    "dropzone",
    "svelte-file-dropzone",
    "svelte-dropzone",
    "sveltejs"
  ],
  "files": [
    "src",
    "dist",
    "!dist/**/*.test.*",
    "!dist/**/*.spec.*"
  ],
  "svelte": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "type": "module"
}


================================================
FILE: renovate.json
================================================
{
  "extends": [
    "config:base"
  ]
}


================================================
FILE: rollup.config.js
================================================
import svelte from "rollup-plugin-svelte";
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import pkg from "./package.json";

const name = pkg.name
  .replace(/^(@\S+\/)?(svelte-)?(\S+)/, "$3")
  .replace(/^\w/, (m) => m.toUpperCase())
  .replace(/-\w/g, (m) => m[1].toUpperCase());

export default {
  input: "src/index.svelte",
  output: [
    { file: pkg.module, format: "es" },
    { file: pkg.main, format: "umd", name },
  ],
  plugins: [svelte(), resolve(), commonjs()],
};


================================================
FILE: src/lib/components/Dropzone.svelte
================================================
<script>
  import { fromEvent } from "file-selector";
  import {
    fileAccepted,
    fileMatchSize,
    isEvtWithFiles,
    isIeOrEdge,
    isPropagationStopped,
    TOO_MANY_FILES_REJECTION
  } from "../utils/index";
  import { onMount, onDestroy, createEventDispatcher } from "svelte";

  //props
  /**
   * Set accepted file types.
   * See https://github.com/okonet/attr-accept for more information.
   */
  /**
   * @type {string | Array<string>}
   */
  export let accept = undefined;
  export let disabled = false;
  export let getFilesFromEvent = fromEvent;
  export let maxSize = Infinity;
  export let minSize = 0;
  export let multiple = true;
  export let preventDropOnDocument = true;
  export let noClick = false;
  export let noKeyboard = false;
  export let noDrag = false;
  export let noDragEventsBubbling = false;
  export let containerClasses = "";
  export let containerStyles = "";
  export let disableDefaultStyles = false;
  export let name = "";
  export let inputElement = undefined;
  export let required = false;
  const dispatch = createEventDispatcher();

  //state

  let state = {
    isFocused: false,
    isFileDialogActive: false,
    isDragActive: false,
    isDragAccept: false,
    isDragReject: false,
    draggedFiles: [],
    acceptedFiles: [],
    fileRejections: []
  };

  let rootRef;

  function resetState() {
    state.isFileDialogActive = false;
    state.isDragActive = false;
    state.draggedFiles = [];
    state.acceptedFiles = [];
    state.fileRejections = [];
  }

  // Fn for opening the file dialog programmatically
  function openFileDialog() {
    if (inputElement) {
      inputElement.value = null; // TODO check if null needs to be set
      state.isFileDialogActive = true;
      inputElement.click();
    }
  }

  // Cb to open the file dialog when SPACE/ENTER occurs on the dropzone
  function onKeyDownCb(event) {
    // Ignore keyboard events bubbling up the DOM tree
    if (!rootRef || !rootRef.isEqualNode(event.target)) {
      return;
    }

    if (event.keyCode === 32 || event.keyCode === 13) {
      event.preventDefault();
      openFileDialog();
    }
  }

  // Update focus state for the dropzone
  function onFocusCb() {
    state.isFocused = true;
  }
  function onBlurCb() {
    state.isFocused = false;
  }

  // Cb to open the file dialog when click occurs on the dropzone
  function onClickCb() {
    if (noClick) {
      return;
    }

    // In IE11/Edge the file-browser dialog is blocking, therefore, use setTimeout()
    // to ensure React can handle state changes
    // See: https://github.com/react-dropzone/react-dropzone/issues/450
    if (isIeOrEdge()) {
      setTimeout(openFileDialog, 0);
    } else {
      openFileDialog();
    }
  }

  function onDragEnterCb(event) {
    event.preventDefault();
    stopPropagation(event);

    dragTargetsRef = [...dragTargetsRef, event.target];

    if (isEvtWithFiles(event)) {
      Promise.resolve(getFilesFromEvent(event)).then(draggedFiles => {
        if (isPropagationStopped(event) && !noDragEventsBubbling) {
          return;
        }

        state.draggedFiles = draggedFiles;
        state.isDragActive = true;

        dispatch("dragenter", {
          dragEvent: event
        });
      });
    }
  }

  function onDragOverCb(event) {
    event.preventDefault();
    stopPropagation(event);

    if (event.dataTransfer) {
      try {
        event.dataTransfer.dropEffect = "copy";
      } catch {} /* eslint-disable-line no-empty */
    }

    if (isEvtWithFiles(event)) {
      dispatch("dragover", {
        dragEvent: event
      });
    }

    return false;
  }

  function onDragLeaveCb(event) {
    event.preventDefault();
    stopPropagation(event);

    // Only deactivate once the dropzone and all children have been left
    const targets = dragTargetsRef.filter(target => rootRef && rootRef.contains(target));
    // Make sure to remove a target present multiple times only once
    // (Firefox may fire dragenter/dragleave multiple times on the same element)
    const targetIdx = targets.indexOf(event.target);
    if (targetIdx !== -1) {
      targets.splice(targetIdx, 1);
    }
    dragTargetsRef = targets;
    if (targets.length > 0) {
      return;
    }

    state.isDragActive = false;
    state.draggedFiles = [];

    if (isEvtWithFiles(event)) {
      dispatch("dragleave", {
        dragEvent: event
      });
    }
  }

  function onDropCb(event) {
    event.preventDefault();
    stopPropagation(event);

    dragTargetsRef = [];

    if (isEvtWithFiles(event)) {
      dispatch("filedropped", {
        event
      });
      Promise.resolve(getFilesFromEvent(event)).then(files => {
        if (isPropagationStopped(event) && !noDragEventsBubbling) {
          return;
        }

        const acceptedFiles = [];
        const fileRejections = [];

        files.forEach(file => {
          const [accepted, acceptError] = fileAccepted(file, accept);
          const [sizeMatch, sizeError] = fileMatchSize(file, minSize, maxSize);
          if (accepted && sizeMatch) {
            acceptedFiles.push(file);
          } else {
            const errors = [acceptError, sizeError].filter(e => e);
            fileRejections.push({ file, errors });
          }
        });

        if (!multiple && acceptedFiles.length > 1) {
          // Reject everything and empty accepted files
          acceptedFiles.forEach(file => {
            fileRejections.push({ file, errors: [TOO_MANY_FILES_REJECTION] });
          });
          acceptedFiles.splice(0);
        }

        // Files dropped keep input in sync
        if (event.dataTransfer) {
          inputElement.files = event.dataTransfer.files;
        }

        state.acceptedFiles = acceptedFiles;
        state.fileRejections = fileRejections;

        dispatch("drop", {
          acceptedFiles,
          fileRejections,
          event
        });

        if (fileRejections.length > 0) {
          dispatch("droprejected", {
            fileRejections,
            event
          });
        }

        if (acceptedFiles.length > 0) {
          dispatch("dropaccepted", {
            acceptedFiles,
            event
          });
        }
      });
    }
    resetState();
  }

  $: composeHandler = fn => (disabled ? null : fn);

  $: composeKeyboardHandler = fn => (noKeyboard ? null : composeHandler(fn));

  $: composeDragHandler = fn => (noDrag ? null : composeHandler(fn));

  $: defaultPlaceholderString = multiple
    ? "Drag 'n' drop some files here, or click to select files"
    : "Drag 'n' drop a file here, or click to select a file";

  function stopPropagation(event) {
    if (noDragEventsBubbling) {
      event.stopPropagation();
    }
  }

  // allow the entire document to be a drag target
  function onDocumentDragOver(event) {
    if (preventDropOnDocument) {
      event.preventDefault();
    }
  }

  let dragTargetsRef = [];
  function onDocumentDrop(event) {
    if (!preventDropOnDocument) {
      return;
    }
    if (rootRef && rootRef.contains(event.target)) {
      // If we intercepted an event for our instance, let it propagate down to the instance's onDrop handler
      return;
    }
    event.preventDefault();
    dragTargetsRef = [];
  }

  // Update file dialog active state when the window is focused on
  function onWindowFocus() {
    // Execute the timeout only if the file dialog is opened in the browser
    if (state.isFileDialogActive) {
      setTimeout(() => {
        if (inputElement) {
          const { files } = inputElement;

          if (!files.length) {
            state.isFileDialogActive = false;
            dispatch("filedialogcancel");
          }
        }
      }, 300);
    }
  }

  onDestroy(() => {
    // This is critical for canceling the timeout behaviour on `onWindowFocus()`
    inputElement = null;
  });

  function onInputElementClick(event) {
    event.stopPropagation();
  }
</script>

<svelte:window on:focus={onWindowFocus} on:dragover={onDocumentDragOver} on:drop={onDocumentDrop} />

<div
  bind:this={rootRef}
  tabindex="0"
  role="button"
  class="{disableDefaultStyles ? '' : 'dropzone'}
  {containerClasses}"
  style={containerStyles}
  on:keydown={composeKeyboardHandler(onKeyDownCb)}
  on:focus={composeKeyboardHandler(onFocusCb)}
  on:blur={composeKeyboardHandler(onBlurCb)}
  on:click={composeHandler(onClickCb)}
  on:dragenter={composeDragHandler(onDragEnterCb)}
  on:dragover={composeDragHandler(onDragOverCb)}
  on:dragleave={composeDragHandler(onDragLeaveCb)}
  on:drop={composeDragHandler(onDropCb)}
  {...$$restProps}
>
  <input
    accept={accept?.toString()}
    {multiple}
    {required}
    type="file"
    {name}
    autocomplete="off"
    tabindex="-1"
    on:change={onDropCb}
    on:click={onInputElementClick}
    bind:this={inputElement}
    style="display: none;"
  />
  <slot>
    <p>{defaultPlaceholderString}</p>
  </slot>
</div>

<style>
  .dropzone {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 20px;
    border-width: 2px;
    border-radius: 2px;
    border-color: #eeeeee;
    border-style: dashed;
    background-color: #fafafa;
    color: #bdbdbd;
    outline: none;
    transition: border 0.24s ease-in-out;
  }
  .dropzone:focus {
    border-color: #2196f3;
  }
</style>


================================================
FILE: src/lib/index.ts
================================================
import Dropzone from "./components/Dropzone.svelte";

export default Dropzone

================================================
FILE: src/lib/utils/attr-accept.js
================================================
/**
 * Check if the provided file type should be accepted by the input with accept attribute.
 * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input#attr-accept
 *
 * Inspired by https://github.com/enyo/dropzone
 *
 * @param file {File} https://developer.mozilla.org/en-US/docs/Web/API/File
 * @param acceptedFiles {string}
 * @returns {boolean}
 */

export default function(file, acceptedFiles) {
  if (file && acceptedFiles) {
    const acceptedFilesArray = Array.isArray(acceptedFiles)
      ? acceptedFiles
      : acceptedFiles.split(",");
    const fileName = file.name || "";
    const mimeType = (file.type || "").toLowerCase();
    const baseMimeType = mimeType.replace(/\/.*$/, "");

    return acceptedFilesArray.some((type) => {
      const validType = type.trim().toLowerCase();
      if (validType.charAt(0) === ".") {
        return fileName.toLowerCase().endsWith(validType);
      } else if (validType.endsWith("/*")) {
        // This is something like a image/* mime type
        return baseMimeType === validType.replace(/\/.*$/, "");
      }
      return mimeType === validType;
    });
  }
  return true;
}


================================================
FILE: src/lib/utils/index.js
================================================
import accepts from "./attr-accept";

// Error codes
export const FILE_INVALID_TYPE = "file-invalid-type";
export const FILE_TOO_LARGE = "file-too-large";
export const FILE_TOO_SMALL = "file-too-small";
export const TOO_MANY_FILES = "too-many-files";

// File Errors
export const getInvalidTypeRejectionErr = (accept) => {
  accept = Array.isArray(accept) && accept.length === 1 ? accept[0] : accept;
  const messageSuffix = Array.isArray(accept)
    ? `one of ${accept.join(", ")}`
    : accept;
  return {
    code: FILE_INVALID_TYPE,
    message: `File type must be ${messageSuffix}`,
  };
};

export const getTooLargeRejectionErr = (maxSize) => {
  return {
    code: FILE_TOO_LARGE,
    message: `File is larger than ${maxSize} bytes`,
  };
};

export const getTooSmallRejectionErr = (minSize) => {
  return {
    code: FILE_TOO_SMALL,
    message: `File is smaller than ${minSize} bytes`,
  };
};

export const TOO_MANY_FILES_REJECTION = {
  code: TOO_MANY_FILES,
  message: "Too many files",
};

// Firefox versions prior to 53 return a bogus MIME type for every file drag, so dragovers with
// that MIME type will always be accepted
export function fileAccepted(file, accept) {
  const isAcceptable =
    file.type === "application/x-moz-file" || accepts(file, accept);
  return [
    isAcceptable,
    isAcceptable ? null : getInvalidTypeRejectionErr(accept),
  ];
}

export function fileMatchSize(file, minSize, maxSize) {
  if (isDefined(file.size)) {
    if (isDefined(minSize) && isDefined(maxSize)) {
      if (file.size > maxSize) return [false, getTooLargeRejectionErr(maxSize)];
      if (file.size < minSize) return [false, getTooSmallRejectionErr(minSize)];
    } else if (isDefined(minSize) && file.size < minSize)
      return [false, getTooSmallRejectionErr(minSize)];
    else if (isDefined(maxSize) && file.size > maxSize)
      return [false, getTooLargeRejectionErr(maxSize)];
  }
  return [true, null];
}

function isDefined(value) {
  return value !== undefined && value !== null;
}

export function allFilesAccepted({
  files,
  accept,
  minSize,
  maxSize,
  multiple,
}) {
  if (!multiple && files.length > 1) {
    return false;
  }

  return files.every((file) => {
    const [accepted] = fileAccepted(file, accept);
    const [sizeMatch] = fileMatchSize(file, minSize, maxSize);
    return accepted && sizeMatch;
  });
}

// React's synthetic events has event.isPropagationStopped,
// but to remain compatibility with other libs (Preact) fall back
// to check event.cancelBubble
export function isPropagationStopped(event) {
  if (typeof event.isPropagationStopped === "function") {
    return event.isPropagationStopped();
  } else if (typeof event.cancelBubble !== "undefined") {
    return event.cancelBubble;
  }
  return false;
}

export function isEvtWithFiles(event) {
  if (!event.dataTransfer) {
    return !!event.target && !!event.target.files;
  }
  // https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/types
  // https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Recommended_drag_types#file
  return Array.prototype.some.call(
    event.dataTransfer.types,
    (type) => type === "Files" || type === "application/x-moz-file"
  );
}

export function isKindFile(item) {
  return typeof item === "object" && item !== null && item.kind === "file";
}

function isIe(userAgent) {
  return (
    userAgent.indexOf("MSIE") !== -1 || userAgent.indexOf("Trident/") !== -1
  );
}

function isEdge(userAgent) {
  return userAgent.indexOf("Edge/") !== -1;
}

export function isIeOrEdge(userAgent = window.navigator.userAgent) {
  return isIe(userAgent) || isEdge(userAgent);
}

/**
 * This is intended to be used to compose event handlers
 * They are executed in order until one of them calls `event.isPropagationStopped()`.
 * Note that the check is done on the first invoke too,
 * meaning that if propagation was stopped before invoking the fns,
 * no handlers will be executed.
 *
 * @param {Function} fns the event hanlder functions
 * @return {Function} the event handler to add to an element
 */
export function composeEventHandlers(...fns) {
  return (event, ...args) =>
    fns.some((fn) => {
      if (!isPropagationStopped(event) && fn) {
        fn(event, ...args);
      }
      return isPropagationStopped(event);
    });
}


================================================
FILE: stories/1-dropzone.stories.js
================================================
//import { action } from "@storybook/addon-actions";

import BasicDropZoneView from "./views/BasicDropzoneView.svelte";
import BasicDropZoneViewSource from "./views/BasicDropzoneView.svelte?raw";
import DisabledDropzoneView from "./views/DisabledDropzoneView.svelte";
import DisabledDropzoneViewSource from "./views/DisabledDropzoneView.svelte?raw";
import CustomSlotDropzoneView from "./views/CustomSlotDropzoneView.svelte";
import CustomSlotDropzoneViewSource from "./views/CustomSlotDropzoneView.svelte?raw";
import NoClickDropZoneView from "./views/NoClickDropzoneView.svelte";
import NoClickDropZoneViewSource from "./views/NoClickDropzoneView.svelte?raw";
import NoDragDropzoneView from "./views/NoDragDropzoneView.svelte";
import NoDragDropzoneViewSource from "./views/NoDragDropzoneView.svelte?raw";

import { sourceParameters } from "./helpers";

export default {
  title: "Examples",
  component: null,
};

export const BasicDropzone = {
  ...sourceParameters(BasicDropZoneViewSource),
  render: () => ({
    Component: BasicDropZoneView,
  }),
};

export const DisabledDropzone = {
  ...sourceParameters(DisabledDropzoneViewSource),
  render: () => ({
    Component: DisabledDropzoneView,
  }),
};

export const CustomSlotDropzone = {
  ...sourceParameters(CustomSlotDropzoneViewSource),
  render: () => ({
    Component: CustomSlotDropzoneView,
  }),
};

export const DropZoneWithClickDisabled = {
  ...sourceParameters(NoClickDropZoneViewSource),
  render: () => ({
    Component: NoClickDropZoneView,
  }),
};

export const DropZoneWithDragDisabled = {
  ...sourceParameters(NoDragDropzoneViewSource),
  render: () => ({
    Component: NoDragDropzoneView,
  }),
};


================================================
FILE: stories/2-advanced-dropzone.stories.js
================================================
import { action } from "@storybook/addon-actions";

import WorkingCSVFileUploadView from "./views/WorkingCSVFileUploadView.svelte";
import WorkingCSVFileUploadViewSource from "./views/WorkingCSVFileUploadView.svelte?raw";
import FullyFeaturedDropzoneView from "./views/FullyFeaturedDropzoneView.svelte";
import FullyFeaturedDropzoneViewSource from "./views/FullyFeaturedDropzoneView.svelte?raw";

import { sourceParameters } from "./helpers";

export default {
  title: "Advanced Examples",
  component: null,
};

export const WorkingCSVFileUploadDropzone = {
  ...sourceParameters(WorkingCSVFileUploadViewSource),
  render: () => ({
    Component: WorkingCSVFileUploadView,
  }),
};

export const FullyFeaturedImagesDropzone = {
  ...sourceParameters(FullyFeaturedDropzoneViewSource),
  render: () => ({
    Component: FullyFeaturedDropzoneView,
  }),
};


================================================
FILE: stories/helpers.js
================================================
export const sourceParameters = (source) => ({
  parameters: {
    docs: {
      source: {
        code: source,
      },
    },
  },
});


================================================
FILE: stories/views/BasicDropzoneAcceptImagesView.svelte
================================================
<script>
  import Dropzone from "../../src/lib/components/Dropzone.svelte";

  let files = {
    accepted: [],
    rejected: [],
  };

  function handleFilesSelect(e) {
    const { acceptedFiles, fileRejections } = e.detail;
    files.accepted = [...files.accepted, ...acceptedFiles];
    files.rejected = [...files.rejected, ...fileRejections];
  }
</script>

<Dropzone on:drop={handleFilesSelect} accept="image/*" />
<ol>
  {#each files.accepted as item}
    <li>{item.name}</li>
  {/each}
</ol>


================================================
FILE: stories/views/BasicDropzoneView.svelte
================================================
<script>
  import Dropzone from "../../src/lib/components/Dropzone.svelte";

  let files = {
    accepted: [],
    rejected: [],
  };

  function handleFilesSelect(e) {
    const { acceptedFiles, fileRejections } = e.detail;
    files.accepted = [...files.accepted, ...acceptedFiles];
    files.rejected = [...files.rejected, ...fileRejections];
  }
</script>

<Dropzone on:drop={handleFilesSelect} />
<ol>
  {#each files.accepted as item}
    <li>{item.name}</li>
  {/each}
</ol>


================================================
FILE: stories/views/CustomSlotDropzoneView.svelte
================================================
<script>
  import Dropzone from "../../src/lib/components/Dropzone.svelte";

  let files = {
    accepted: [],
    rejected: [],
  };

  function handleFilesSelect(e) {
    const { acceptedFiles, fileRejections } = e.detail;
    files.accepted = [...files.accepted, ...acceptedFiles];
    files.rejected = [...files.rejected, ...fileRejections];
  }
</script>

<Dropzone on:drop={handleFilesSelect}>
  <p>Custom Slot Dropzone</p>
</Dropzone>
<ol>
  {#each files.accepted as item}
    <li>{item.name}</li>
  {/each}
</ol>


================================================
FILE: stories/views/DisabledDropzoneView.svelte
================================================
<script>
  import Dropzone from "../../src/lib/components/Dropzone.svelte";

  let files = {
    accepted: [],
    rejected: [],
  };

  function handleFilesSelect(e) {
    const { acceptedFiles, fileRejections } = e.detail;
    files.accepted = [...files.accepted, ...acceptedFiles];
    files.rejected = [...files.rejected, ...fileRejections];
  }
</script>

<Dropzone on:drop={handleFilesSelect} disabled />
<ol>
  {#each files.accepted as item}
    <li>{item.name}</li>
  {/each}
</ol>


================================================
FILE: stories/views/FullyFeaturedDropzoneView.svelte
================================================
<script>
  import Dropzone from "../../src/lib/components/Dropzone.svelte";

  let files = {
    accepted: [],
    rejected: [],
  };

  function handleFilesSelect(e) {
    const { acceptedFiles, fileRejections } = e.detail;
    files.accepted = [...files.accepted, ...acceptedFiles];
    files.rejected = [...files.rejected, ...fileRejections];
  }

  function handleRemoveFile(e, index) {
    files.accepted.splice(index, 1);
    files.accepted = [...files.accepted];
  }
  function handleRemoveAll() {
    files.accepted = [];
  }
</script>

<Dropzone on:drop={handleFilesSelect} accept={["image/*"]} containerClasses="custom-dropzone">
  <button>Choose images to upload</button>

  <p>or</p>
  <p>Drag and drop them here</p>
</Dropzone>
<div style="margin: 5px;">
  {#if files.accepted.length > 0}
    <button on:click={handleRemoveAll}>RemoveAll</button>
  {/if}
  {#each files.accepted as item, index}
    <div>
      <span>{item.name}</span>
      <button on:click={(e) => handleRemoveFile(e, index)}>Remove</button>
    </div>
  {/each}
</div>

<style>
  :global(.custom-dropzone) {
  }
</style>


================================================
FILE: stories/views/NoClickDropzoneView.svelte
================================================
<script>
  import Dropzone from "../../src/lib/components/Dropzone.svelte";

  let files = {
    accepted: [],
    rejected: [],
  };

  function handleFilesSelect(e) {
    const { acceptedFiles, fileRejections } = e.detail;
    files.accepted = [...files.accepted, ...acceptedFiles];
    files.rejected = [...files.rejected, ...fileRejections];
  }
</script>

<Dropzone on:drop={handleFilesSelect} noClick />
<ol>
  {#each files.accepted as item}
    <li>{item.name}</li>
  {/each}
</ol>


================================================
FILE: stories/views/NoDragDropzoneView.svelte
================================================
<script>
  import Dropzone from "../../src/lib/components/Dropzone.svelte";

  let files = {
    accepted: [],
    rejected: [],
  };

  function handleFilesSelect(e) {
    const { acceptedFiles, fileRejections } = e.detail;
    files.accepted = [...files.accepted, ...acceptedFiles];
    files.rejected = [...files.rejected, ...fileRejections];
  }
</script>

<Dropzone on:drop={handleFilesSelect} noDrag />
<ol>
  {#each files.accepted as item}
    <li>{item.name}</li>
  {/each}
</ol>


================================================
FILE: stories/views/WorkingCSVFileUploadView.svelte
================================================
<script>
  import Dropzone from "../../src/lib/components/Dropzone.svelte";

  let files = [];
  let fileData = [];

  function processRawCSV(data) {
    const output = [];
    const rows = data.split("\n");
    for (let i = 0; i < rows.length; i++) {
      const cells = rows[i].split(",");
      output.push(cells);
    }
    return output;
  }

  function handleFilesSelect(e) {
    files = e.detail.acceptedFiles;

    for (let i = 0; i < files.length; i++) {
      const reader = new FileReader();
      reader.onload = () => {
        const binaryStr = reader.result;
        fileData = processRawCSV(binaryStr);
      };
      console.log(reader.readAsText(files[i]));
    }
  }
</script>

<h1>Upload CSV file and preview same</h1>
<Dropzone on:drop={handleFilesSelect} multiple={false} accept=".csv" />

{#each files as item}
  <h2>{item.name}</h2>
{/each}

<table border="1">
  {#each fileData as row}
    <tr>
      {#each row as item}
        <td>{item}</td>
      {/each}
    </tr>
  {/each}
</table>
Download .txt
gitextract_nknodkyk/

├── .gitignore
├── .prettierrc
├── .storybook/
│   ├── main.js
│   └── preview-head.html
├── README.md
├── TODO
├── demo/
│   ├── .gitignore
│   ├── .npmrc
│   ├── .prettierignore
│   ├── .prettierrc
│   ├── README.md
│   ├── package.json
│   ├── src/
│   │   ├── app.d.ts
│   │   ├── app.html
│   │   ├── index.test.ts
│   │   ├── lib/
│   │   │   └── index.ts
│   │   └── routes/
│   │       ├── basic/
│   │       │   └── +page.svelte
│   │       ├── custom-props/
│   │       │   └── +page.svelte
│   │       ├── form/
│   │       │   ├── +page.server.ts
│   │       │   └── +page.svelte
│   │       ├── reactive-disabled/
│   │       │   └── +page.svelte
│   │       └── toggle-multiple/
│   │           └── +page.svelte
│   ├── svelte.config.js
│   ├── tsconfig.json
│   └── vite.config.ts
├── jsconfig.json
├── package.json
├── renovate.json
├── rollup.config.js
├── src/
│   └── lib/
│       ├── components/
│       │   └── Dropzone.svelte
│       ├── index.ts
│       └── utils/
│           ├── attr-accept.js
│           └── index.js
└── stories/
    ├── 1-dropzone.stories.js
    ├── 2-advanced-dropzone.stories.js
    ├── helpers.js
    └── views/
        ├── BasicDropzoneAcceptImagesView.svelte
        ├── BasicDropzoneView.svelte
        ├── CustomSlotDropzoneView.svelte
        ├── DisabledDropzoneView.svelte
        ├── FullyFeaturedDropzoneView.svelte
        ├── NoClickDropzoneView.svelte
        ├── NoDragDropzoneView.svelte
        └── WorkingCSVFileUploadView.svelte
Download .txt
SYMBOL INDEX (17 symbols across 2 files)

FILE: demo/src/routes/form/+page.server.ts
  method postFiles (line 2) | async postFiles({ request }) {

FILE: src/lib/utils/index.js
  constant FILE_INVALID_TYPE (line 4) | const FILE_INVALID_TYPE = "file-invalid-type";
  constant FILE_TOO_LARGE (line 5) | const FILE_TOO_LARGE = "file-too-large";
  constant FILE_TOO_SMALL (line 6) | const FILE_TOO_SMALL = "file-too-small";
  constant TOO_MANY_FILES (line 7) | const TOO_MANY_FILES = "too-many-files";
  constant TOO_MANY_FILES_REJECTION (line 35) | const TOO_MANY_FILES_REJECTION = {
  function fileAccepted (line 42) | function fileAccepted(file, accept) {
  function fileMatchSize (line 51) | function fileMatchSize(file, minSize, maxSize) {
  function isDefined (line 64) | function isDefined(value) {
  function allFilesAccepted (line 68) | function allFilesAccepted({
  function isPropagationStopped (line 89) | function isPropagationStopped(event) {
  function isEvtWithFiles (line 98) | function isEvtWithFiles(event) {
  function isKindFile (line 110) | function isKindFile(item) {
  function isIe (line 114) | function isIe(userAgent) {
  function isEdge (line 120) | function isEdge(userAgent) {
  function isIeOrEdge (line 124) | function isIeOrEdge(userAgent = window.navigator.userAgent) {
  function composeEventHandlers (line 138) | function composeEventHandlers(...fns) {
Condensed preview — 44 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (46K chars).
[
  {
    "path": ".gitignore",
    "chars": 81,
    "preview": "node_modules\r\ndist\r\nstorybook-static\r\npackage-lock.json\r\n.DS_Store\r\n.svelte-kit\r\n"
  },
  {
    "path": ".prettierrc",
    "chars": 233,
    "preview": "{\n\t\"useTabs\": false,\n\t\"singleQuote\": false,\n\t\"trailingComma\": \"none\",\n\t\"printWidth\": 100,\n\t\"plugins\": [\"prettier-plugin-"
  },
  {
    "path": ".storybook/main.js",
    "chars": 271,
    "preview": "export default {\n  stories: [\"../stories/**/*.stories.js\"],\n  addons: [\"@storybook/addon-links\", \"@storybook/addon-essen"
  },
  {
    "path": ".storybook/preview-head.html",
    "chars": 45,
    "preview": "<script>\n  window.global = window;\n</script>\n"
  },
  {
    "path": "README.md",
    "chars": 4557,
    "preview": "# svelte-file-dropzone\r\n\r\n[![NPM](https://img.shields.io/npm/v/svelte-file-dropzone.svg)](https://www.npmjs.com/package/"
  },
  {
    "path": "TODO",
    "chars": 411,
    "preview": "\nTodo:\n  ✔ Git repo @done(20-06-17 21:58)\n  ✔ npm initial publish @done(20-06-18 22:34)\n  ✔ setup netlify @done(20-06-17"
  },
  {
    "path": "demo/.gitignore",
    "chars": 132,
    "preview": ".DS_Store\nnode_modules\n/build\n/.svelte-kit\n/package\n.env\n.env.*\n!.env.example\nvite.config.js.timestamp-*\nvite.config.ts."
  },
  {
    "path": "demo/.npmrc",
    "chars": 19,
    "preview": "engine-strict=true\n"
  },
  {
    "path": "demo/.prettierignore",
    "chars": 81,
    "preview": "# Ignore files for PNPM, NPM and YARN\npnpm-lock.yaml\npackage-lock.json\nyarn.lock\n"
  },
  {
    "path": "demo/.prettierrc",
    "chars": 205,
    "preview": "{\n\t\"useTabs\": true,\n\t\"singleQuote\": true,\n\t\"trailingComma\": \"none\",\n\t\"printWidth\": 100,\n\t\"plugins\": [\"prettier-plugin-sv"
  },
  {
    "path": "demo/README.md",
    "chars": 942,
    "preview": "# create-svelte\n\nEverything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs"
  },
  {
    "path": "demo/package.json",
    "chars": 754,
    "preview": "{\n\t\"name\": \"demo\",\n\t\"version\": \"0.0.1\",\n\t\"private\": true,\n\t\"scripts\": {\n\t\t\"dev\": \"vite dev\",\n\t\t\"build\": \"vite build\",\n\t\t"
  },
  {
    "path": "demo/src/app.d.ts",
    "chars": 269,
    "preview": "// See https://kit.svelte.dev/docs/types#app\n// for information about these interfaces\ndeclare global {\n\tnamespace App {"
  },
  {
    "path": "demo/src/app.html",
    "chars": 346,
    "preview": "<!doctype html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<link rel=\"icon\" href=\"%sveltekit.assets%/favicon."
  },
  {
    "path": "demo/src/index.test.ts",
    "chars": 148,
    "preview": "import { describe, it, expect } from 'vitest';\n\ndescribe('sum test', () => {\n\tit('adds 1 + 2 to equal 3', () => {\n\t\texpe"
  },
  {
    "path": "demo/src/lib/index.ts",
    "chars": 75,
    "preview": "// place files you want to import through the `$lib` alias in this folder.\n"
  },
  {
    "path": "demo/src/routes/basic/+page.svelte",
    "chars": 664,
    "preview": "<script lang=\"ts\">\n\timport Dropzone from '../../../../src/lib/components/Dropzone.svelte';\n\n\tlet files = {\n\t\taccepted: ["
  },
  {
    "path": "demo/src/routes/custom-props/+page.svelte",
    "chars": 807,
    "preview": "<script lang=\"ts\">\n\timport Dropzone from '../../../../src/lib/components/Dropzone.svelte';\n\n\tlet files = {\n\t\taccepted: ["
  },
  {
    "path": "demo/src/routes/form/+page.server.ts",
    "chars": 216,
    "preview": "export const actions = {\n\tasync postFiles({ request }) {\n\t\tconst formData: FormData = await request.formData();\n\t\tconst "
  },
  {
    "path": "demo/src/routes/form/+page.svelte",
    "chars": 702,
    "preview": "<script lang=\"ts\">\n\timport { enhance } from '$app/forms';\n\timport { page } from '$app/stores';\n\timport Dropzone from '.."
  },
  {
    "path": "demo/src/routes/reactive-disabled/+page.svelte",
    "chars": 925,
    "preview": "<script lang=\"ts\">\n\timport Dropzone from '../../../../src/lib/components/Dropzone.svelte';\n\n\tlet files = {\n\t\taccepted: ["
  },
  {
    "path": "demo/src/routes/toggle-multiple/+page.svelte",
    "chars": 774,
    "preview": "<script lang=\"ts\">\n\timport Dropzone from '../../../../src/lib/components/Dropzone.svelte';\n\n\tlet files = {\n\t\taccepted: ["
  },
  {
    "path": "demo/svelte.config.js",
    "chars": 675,
    "preview": "import adapter from '@sveltejs/adapter-auto';\nimport { vitePreprocess } from '@sveltejs/vite-plugin-svelte';\n\n/** @type "
  },
  {
    "path": "demo/tsconfig.json",
    "chars": 565,
    "preview": "{\n\t\"extends\": \"./.svelte-kit/tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true,\n\t\t\"checkJs\": true,\n\t\t\"esModuleInte"
  },
  {
    "path": "demo/vite.config.ts",
    "chars": 210,
    "preview": "import { sveltekit } from '@sveltejs/kit/vite';\nimport { defineConfig } from 'vitest/config';\n\nexport default defineConf"
  },
  {
    "path": "jsconfig.json",
    "chars": 3,
    "preview": "{}\n"
  },
  {
    "path": "package.json",
    "chars": 1695,
    "preview": "{\n  \"name\": \"svelte-file-dropzone\",\n  \"version\": \"2.0.9\",\n  \"description\": \"Svelte component for fileupload and file dro"
  },
  {
    "path": "renovate.json",
    "chars": 41,
    "preview": "{\n  \"extends\": [\n    \"config:base\"\n  ]\n}\n"
  },
  {
    "path": "rollup.config.js",
    "chars": 532,
    "preview": "import svelte from \"rollup-plugin-svelte\";\nimport resolve from \"@rollup/plugin-node-resolve\";\nimport commonjs from \"@rol"
  },
  {
    "path": "src/lib/components/Dropzone.svelte",
    "chars": 9663,
    "preview": "<script>\r\n  import { fromEvent } from \"file-selector\";\r\n  import {\r\n    fileAccepted,\r\n    fileMatchSize,\r\n    isEvtWith"
  },
  {
    "path": "src/lib/index.ts",
    "chars": 77,
    "preview": "import Dropzone from \"./components/Dropzone.svelte\";\n\nexport default Dropzone"
  },
  {
    "path": "src/lib/utils/attr-accept.js",
    "chars": 1174,
    "preview": "/**\r\n * Check if the provided file type should be accepted by the input with accept attribute.\r\n * https://developer.moz"
  },
  {
    "path": "src/lib/utils/index.js",
    "chars": 4453,
    "preview": "import accepts from \"./attr-accept\";\r\n\r\n// Error codes\r\nexport const FILE_INVALID_TYPE = \"file-invalid-type\";\r\nexport co"
  },
  {
    "path": "stories/1-dropzone.stories.js",
    "chars": 1733,
    "preview": "//import { action } from \"@storybook/addon-actions\";\r\n\r\nimport BasicDropZoneView from \"./views/BasicDropzoneView.svelte\""
  },
  {
    "path": "stories/2-advanced-dropzone.stories.js",
    "chars": 883,
    "preview": "import { action } from \"@storybook/addon-actions\";\r\n\r\nimport WorkingCSVFileUploadView from \"./views/WorkingCSVFileUpload"
  },
  {
    "path": "stories/helpers.js",
    "chars": 138,
    "preview": "export const sourceParameters = (source) => ({\n  parameters: {\n    docs: {\n      source: {\n        code: source,\n      }"
  },
  {
    "path": "stories/views/BasicDropzoneAcceptImagesView.svelte",
    "chars": 519,
    "preview": "<script>\r\n  import Dropzone from \"../../src/lib/components/Dropzone.svelte\";\r\n\r\n  let files = {\r\n    accepted: [],\r\n    "
  },
  {
    "path": "stories/views/BasicDropzoneView.svelte",
    "chars": 502,
    "preview": "<script>\r\n  import Dropzone from \"../../src/lib/components/Dropzone.svelte\";\r\n\r\n  let files = {\r\n    accepted: [],\r\n    "
  },
  {
    "path": "stories/views/CustomSlotDropzoneView.svelte",
    "chars": 544,
    "preview": "<script>\r\n  import Dropzone from \"../../src/lib/components/Dropzone.svelte\";\r\n\r\n  let files = {\r\n    accepted: [],\r\n    "
  },
  {
    "path": "stories/views/DisabledDropzoneView.svelte",
    "chars": 511,
    "preview": "<script>\r\n  import Dropzone from \"../../src/lib/components/Dropzone.svelte\";\r\n\r\n  let files = {\r\n    accepted: [],\r\n    "
  },
  {
    "path": "stories/views/FullyFeaturedDropzoneView.svelte",
    "chars": 1149,
    "preview": "<script>\r\n  import Dropzone from \"../../src/lib/components/Dropzone.svelte\";\r\n\r\n  let files = {\r\n    accepted: [],\r\n    "
  },
  {
    "path": "stories/views/NoClickDropzoneView.svelte",
    "chars": 510,
    "preview": "<script>\r\n  import Dropzone from \"../../src/lib/components/Dropzone.svelte\";\r\n\r\n  let files = {\r\n    accepted: [],\r\n    "
  },
  {
    "path": "stories/views/NoDragDropzoneView.svelte",
    "chars": 509,
    "preview": "<script>\r\n  import Dropzone from \"../../src/lib/components/Dropzone.svelte\";\r\n\r\n  let files = {\r\n    accepted: [],\r\n    "
  },
  {
    "path": "stories/views/WorkingCSVFileUploadView.svelte",
    "chars": 1059,
    "preview": "<script>\r\n  import Dropzone from \"../../src/lib/components/Dropzone.svelte\";\r\n\r\n  let files = [];\r\n  let fileData = [];\r"
  }
]

About this extraction

This page contains the full source code of the thecodejack/svelte-file-dropzone GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 44 files (38.9 KB), approximately 11.3k tokens, and a symbol index with 17 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!