Selaa lähdekoodia

Svelte integration (#2671)

* Added basic components

* Updated README

* Added LICENSE

* Added basic doucmentation

* svelte: Fixed CSS issues

* svelte: Added CSS to docs

* svelte: Removed favicon

* svelte: Configured build system and CSS

* svelte: Updated docs for better CSS

* svelte: Disable TSD for svelte

* fix: fixed svelte building issues

* Update packages/@uppy/svelte/package.json

Co-authored-by: Artur Paikin <artur@arturpaikin.com>

* add svelte to locale-packes build ignore

* upgrade typescript

This might get reverted, but it upgrades from Typescript version 3.7.5 to 3.9.3

* remove devDependencies from svelte and vue packages

* Update packages/@uppy/svelte/package.json

Co-authored-by: Renée Kooi <renee@kooi.me>

* slight tweak for docs and readme

* try to switch to file urls for vue and svelte

Co-authored-by: Artur Paikin <artur@arturpaikin.com>
Co-authored-by: Renée Kooi <renee@kooi.me>
Andrew 4 vuotta sitten
vanhempi
commit
ff3127f663

+ 1 - 1
bin/build-lib.js

@@ -12,7 +12,7 @@ const stat = promisify(fs.stat)
 
 const SOURCE = 'packages/{*,@uppy/*}/src/**/*.js'
 // Files not to build (such as tests)
-const IGNORE = /\.test\.js$|__mocks__|companion\//
+const IGNORE = /\.test\.js$|__mocks__|svelte|companion\//
 // Files that should trigger a rebuild of everything on change
 const META_FILES = [
   'babel.config.js',

+ 4 - 1
bin/locale-packs.js

@@ -52,7 +52,10 @@ function buildPluginsList () {
   for (const file of files) {
     const dirName = path.dirname(file)
     const pluginName = path.basename(dirName)
-    if (pluginName === 'locales' || pluginName === 'react-native' || pluginName === 'vue') {
+    if (pluginName === 'locales' ||
+        pluginName === 'react-native' ||
+        pluginName === 'vue' ||
+        pluginName === 'svelte') {
       continue
     }
     const Plugin = require(dirName)

+ 5 - 0
examples/svelte-example/.gitignore

@@ -0,0 +1,5 @@
+/node_modules/
+/public/build/
+
+.DS_Store
+package-lock.json

+ 3 - 0
examples/svelte-example/README.md

@@ -0,0 +1,3 @@
+# `svelte-example`
+
+More info coming soon...

+ 37 - 0
examples/svelte-example/package.json

@@ -0,0 +1,37 @@
+{
+  "name": "svelte-app",
+  "version": "1.0.0",
+  "scripts": {
+    "build": "rollup -c",
+    "dev": "rollup -c -w",
+    "start": "sirv public",
+    "validate": "svelte-check"
+  },
+  "devDependencies": {
+    "@rollup/plugin-commonjs": "^16.0.0",
+    "@rollup/plugin-json": "^4.1.0",
+    "@rollup/plugin-node-resolve": "^10.0.0",
+    "@rollup/plugin-typescript": "^6.0.0",
+    "@tsconfig/svelte": "^1.0.0",
+    "postcss": "^8.2.1",
+    "postcss-import": "^13.0.0",
+    "postcss-load-config": "^3.0.0",
+    "rollup": "^2.3.4",
+    "rollup-plugin-css-only": "^3.0.0",
+    "rollup-plugin-livereload": "^2.0.0",
+    "rollup-plugin-svelte": "^7.0.0",
+    "rollup-plugin-terser": "^7.0.0",
+    "svelte": ">=3.24.0",
+    "svelte-check": "^1.0.0",
+    "svelte-preprocess": "^4.6.1",
+    "tslib": "^2.0.0",
+    "typescript": "^3.9.3"
+  },
+  "dependencies": {
+    "@uppy/core": "^1.14.1",
+    "@uppy/svelte": "../../packages/@uppy/svelte",
+    "@uppy/webcam": "^1.8.1",
+    "@uppy/xhr-upload": "^1.6.7",
+    "sirv-cli": "^1.0.0"
+  }
+}

+ 5 - 0
examples/svelte-example/postcss.config.js

@@ -0,0 +1,5 @@
+module.exports = {
+  plugins: [
+    require('postcss-import')()
+  ]
+}

+ 67 - 0
examples/svelte-example/public/global.css

@@ -0,0 +1,67 @@
+html,
+body {
+  position: relative;
+  width: 100%;
+  height: 100%;
+}
+
+body {
+  color: #333;
+  margin: 0;
+  padding: 8px;
+  box-sizing: border-box;
+  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
+}
+
+a {
+  color: rgb(0, 100, 200);
+  text-decoration: none;
+}
+
+a:hover {
+  text-decoration: underline;
+}
+
+a:visited {
+  color: rgb(0, 80, 160);
+}
+
+label {
+  display: block;
+}
+
+input,
+button,
+select,
+textarea {
+  font-family: inherit;
+  font-size: inherit;
+  -webkit-padding: 0.4em 0;
+  padding: 0.4em;
+  margin: 0 0 0.5em 0;
+  box-sizing: border-box;
+  border: 1px solid #ccc;
+  border-radius: 2px;
+}
+
+input:disabled {
+  color: #ccc;
+}
+
+button {
+  color: #333;
+  background-color: #f4f4f4;
+  outline: none;
+}
+
+button:disabled {
+  color: #999;
+}
+
+button:not(:disabled):active {
+  background-color: #ddd;
+}
+
+button:focus {
+  border-color: #666;
+}

+ 17 - 0
examples/svelte-example/public/index.html

@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+	<meta charset='utf-8'>
+	<meta name='viewport' content='width=device-width,initial-scale=1'>
+
+	<title>Svelte app</title>
+
+	<link rel='icon' type='image/png' href='/favicon.png'>
+	<link rel='stylesheet' href='/global.css'>
+	<link rel='stylesheet' href='/build/bundle.css'>
+	<script defer src='/build/bundle.js'></script>
+</head>
+
+<body>
+</body>
+</html>

+ 85 - 0
examples/svelte-example/rollup.config.js

@@ -0,0 +1,85 @@
+import svelte from 'rollup-plugin-svelte'
+import commonjs from '@rollup/plugin-commonjs'
+import resolve from '@rollup/plugin-node-resolve'
+import livereload from 'rollup-plugin-livereload'
+import { terser } from 'rollup-plugin-terser'
+import sveltePreprocess from 'svelte-preprocess'
+import typescript from '@rollup/plugin-typescript'
+import css from 'rollup-plugin-css-only'
+
+const production = !process.env.ROLLUP_WATCH
+
+function serve () {
+  let server
+
+  function toExit () {
+    if (server) server.kill(0)
+  }
+
+  return {
+    writeBundle () {
+      if (server) return
+      server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
+        stdio: ['ignore', 'inherit', 'inherit'],
+        shell: true
+      })
+
+      process.on('SIGTERM', toExit)
+      process.on('exit', toExit)
+    }
+  }
+}
+
+export default {
+  input: 'src/main.ts',
+  output: {
+    sourcemap: true,
+    format: 'iife',
+    name: 'app',
+    file: 'public/build/bundle.js'
+  },
+  plugins: [
+    svelte({
+      preprocess: sveltePreprocess({
+        postcss: true
+      }),
+      compilerOptions: {
+        // enable run-time checks when not in production
+        dev: !production
+      }
+    }),
+    // we'll extract any component CSS out into
+    // a separate file - better for performance
+    css({ output: 'bundle.css' }),
+
+    // If you have external dependencies installed from
+    // npm, you'll most likely need these plugins. In
+    // some cases you'll need additional configuration -
+    // consult the documentation for details:
+    // https://github.com/rollup/plugins/tree/master/packages/commonjs
+    resolve({
+      browser: true,
+      dedupe: ['svelte', '@uppy/core']
+    }),
+    commonjs(),
+    typescript({
+      sourceMap: !production,
+      inlineSources: !production
+    }),
+
+    // In dev mode, call `npm run start` once
+    // the bundle has been generated
+    !production && serve(),
+
+    // Watch the `public` directory and refresh the
+    // browser on changes when not in production
+    !production && livereload('public'),
+
+    // If we're building for production (npm run build
+    // instead of npm run dev), minify
+    production && terser()
+  ],
+  watch: {
+    clearScreen: false
+  }
+}

+ 71 - 0
examples/svelte-example/src/App.svelte

@@ -0,0 +1,71 @@
+<script lang="ts">
+	import { Dashboard, DashboardModal, DragDrop, ProgressBar } from "@uppy/svelte"
+	import Uppy from "@uppy/core"
+	import Webcam from '@uppy/webcam'
+	import XHRUpload from '@uppy/xhr-upload'
+
+	let createUppy = () => Uppy().use(Webcam).use(XHRUpload, {
+		bundle: true,
+		endpoint: 'http://localhost:9967/upload',
+		metaFields: ['something'],
+		fieldName: 'files'
+	})
+
+	let uppy1 = createUppy()
+	let uppy2 = createUppy() 
+
+	let open = false;
+	let showInlineDashboard = true;
+</script>
+
+<main>
+	<h1>Welcome to the <code>@uppy/svelte</code> demo!</h1>
+	<h2>Inline Dashboard</h2>
+	<label>
+      <input
+        type="checkbox"
+				bind:checked={showInlineDashboard}
+			/>
+      Show Dashboard
+	</label>
+	{#if showInlineDashboard}
+		<Dashboard 
+			uppy={uppy1}
+			plugins={['Webcam']}
+		/>
+	{/if}
+	<h2>Modal Dashboard</h2>
+	<div>
+		<button on:click={() => open = true}>Show Dashboard</button>
+		<DashboardModal 
+			uppy={uppy2} 
+			open={open} 
+			props={{
+				onRequestCloseModal: () => open = false,
+				plugins: ['Webcam']
+			}} 
+		/>
+	</div>
+
+	<h2>Drag Drop Area</h2>
+	<DragDrop 
+		uppy={uppy1}
+	/>
+
+	<h2>Progress Bar</h2>
+	<ProgressBar 
+		uppy={uppy1}
+		props={{
+			hideAfterFinish: false
+		}}
+	/>
+</main>
+<style global>
+	@import "@uppy/core/dist/style.min.css";
+	@import "@uppy/dashboard/dist/style.min.css";
+	@import "@uppy/drag-drop/dist/style.min.css";
+	@import "@uppy/progress-bar/dist/style.min.css";
+	input[type="checkbox"] {
+		user-select: none;
+	}
+</style>

+ 7 - 0
examples/svelte-example/src/main.ts

@@ -0,0 +1,7 @@
+import App from './App.svelte';
+
+const app = new App({
+	target: document.body,
+});
+
+export default app;

+ 8 - 0
examples/svelte-example/tsconfig.json

@@ -0,0 +1,8 @@
+{
+  "extends": "@tsconfig/svelte/tsconfig.json",
+  "compilerOptions": {
+  },
+  "esModuleInterop": true,
+  "include": ["src/**/*"],
+  "exclude": ["node_modules/*", "__sapper__/*", "public/*"]
+}

+ 370 - 4
package-lock.json

@@ -6938,6 +6938,43 @@
       "resolved": "https://registry.npmjs.org/@request/interface/-/interface-0.1.0.tgz",
       "integrity": "sha1-yRNQTT3CgQr61VW1ma6uwsxMZ2g="
     },
+    "@rollup/plugin-node-resolve": {
+      "version": "11.0.1",
+      "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.0.1.tgz",
+      "integrity": "sha512-ltlsj/4Bhwwhb+Nb5xCz/6vieuEj2/BAkkqVIKmZwC7pIdl8srmgmglE4S0jFlZa32K4qvdQ6NHdmpRKD/LwoQ==",
+      "dev": true,
+      "requires": {
+        "@rollup/pluginutils": "^3.1.0",
+        "@types/resolve": "1.17.1",
+        "builtin-modules": "^3.1.0",
+        "deepmerge": "^4.2.2",
+        "is-module": "^1.0.0",
+        "resolve": "^1.19.0"
+      },
+      "dependencies": {
+        "resolve": {
+          "version": "1.19.0",
+          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz",
+          "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==",
+          "dev": true,
+          "requires": {
+            "is-core-module": "^2.1.0",
+            "path-parse": "^1.0.6"
+          }
+        }
+      }
+    },
+    "@rollup/pluginutils": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
+      "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==",
+      "dev": true,
+      "requires": {
+        "@types/estree": "0.0.39",
+        "estree-walker": "^1.0.1",
+        "picomatch": "^2.2.2"
+      }
+    },
     "@samverschueren/stream-to-observable": {
       "version": "0.3.1",
       "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.1.tgz",
@@ -7050,6 +7087,12 @@
       "resolved": "https://registry.npmjs.org/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz",
       "integrity": "sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA=="
     },
+    "@tsconfig/svelte": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-1.0.10.tgz",
+      "integrity": "sha512-EBrpH2iXXfaf/9z81koiDYkp2mlwW2XzFcAqn6qh7VKyP8zBvHHAQzNhY+W9vH5arAjmGAm5g8ElWq6YmXm3ig==",
+      "dev": true
+    },
     "@types/aws-lambda": {
       "version": "8.10.64",
       "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.64.tgz",
@@ -7181,6 +7224,12 @@
         "@types/express": "*"
       }
     },
+    "@types/estree": {
+      "version": "0.0.39",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
+      "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
+      "dev": true
+    },
     "@types/express": {
       "version": "4.17.8",
       "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.8.tgz",
@@ -7391,6 +7440,12 @@
       "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==",
       "dev": true
     },
+    "@types/pug": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.4.tgz",
+      "integrity": "sha1-h3L80EGOPNLMFxVV1zAHQVBR9LI=",
+      "dev": true
+    },
     "@types/q": {
       "version": "1.5.4",
       "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz",
@@ -7451,6 +7506,24 @@
         }
       }
     },
+    "@types/resolve": {
+      "version": "1.17.1",
+      "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
+      "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*"
+      }
+    },
+    "@types/sass": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/@types/sass/-/sass-1.16.0.tgz",
+      "integrity": "sha512-2XZovu4NwcqmtZtsBR5XYLw18T8cBCnU2USFHTnYLLHz9fkhnoEMoDsqShJIOFsFhn5aJHjweiUUdTrDGujegA==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*"
+      }
+    },
     "@types/serve-static": {
       "version": "1.13.6",
       "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.6.tgz",
@@ -8589,6 +8662,7 @@
       "requires": {
         "@uppy/dashboard": "file:packages/@uppy/dashboard",
         "@uppy/drag-drop": "file:packages/@uppy/drag-drop",
+        "@uppy/file-input": "file:packages/@uppy/file-input",
         "@uppy/progress-bar": "file:packages/@uppy/progress-bar",
         "@uppy/status-bar": "file:packages/@uppy/status-bar",
         "@uppy/utils": "file:packages/@uppy/utils",
@@ -8654,6 +8728,15 @@
         "cuid": "^2.1.1"
       }
     },
+    "@uppy/svelte": {
+      "version": "file:packages/@uppy/svelte",
+      "requires": {
+        "@uppy/dashboard": "file:packages/@uppy/dashboard",
+        "@uppy/drag-drop": "file:packages/@uppy/drag-drop",
+        "@uppy/progress-bar": "file:packages/@uppy/progress-bar",
+        "@uppy/status-bar": "file:packages/@uppy/status-bar"
+      }
+    },
     "@uppy/thumbnail-generator": {
       "version": "file:packages/@uppy/thumbnail-generator",
       "requires": {
@@ -12979,6 +13062,12 @@
       "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
       "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk="
     },
+    "builtin-modules": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz",
+      "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==",
+      "dev": true
+    },
     "builtin-status-codes": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
@@ -18353,6 +18442,12 @@
         "estree-is-identifier": "^1.0.0"
       }
     },
+    "estree-walker": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
+      "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==",
+      "dev": true
+    },
     "esutils": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
@@ -23448,6 +23543,12 @@
         }
       }
     },
+    "is-module": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
+      "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
+      "dev": true
+    },
     "is-nan": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.0.tgz",
@@ -36462,6 +36563,12 @@
         "is-nil-x": "^2.1.1"
       }
     },
+    "require-relative": {
+      "version": "0.8.7",
+      "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz",
+      "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=",
+      "dev": true
+    },
     "requires-port": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
@@ -36646,6 +36753,51 @@
         "inherits": "^2.0.1"
       }
     },
+    "rollup": {
+      "version": "2.35.1",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.35.1.tgz",
+      "integrity": "sha512-q5KxEyWpprAIcainhVy6HfRttD9kutQpHbeqDTWnqAFNJotiojetK6uqmcydNMymBEtC4I8bCYR+J3mTMqeaUA==",
+      "dev": true,
+      "requires": {
+        "fsevents": "~2.1.2"
+      },
+      "dependencies": {
+        "fsevents": {
+          "version": "2.1.3",
+          "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
+          "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
+    "rollup-plugin-svelte": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/rollup-plugin-svelte/-/rollup-plugin-svelte-7.0.0.tgz",
+      "integrity": "sha512-cw4yv/5v1NQV3nPbpOJtikgkB+9mfSJaqKUdq7x5fVQJnwLtcdc2JOszBs5pBY+SemTs5pmJbdEMseEavbUtjQ==",
+      "dev": true,
+      "requires": {
+        "require-relative": "^0.8.7",
+        "rollup-pluginutils": "^2.8.2"
+      }
+    },
+    "rollup-pluginutils": {
+      "version": "2.8.2",
+      "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
+      "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
+      "dev": true,
+      "requires": {
+        "estree-walker": "^0.6.1"
+      },
+      "dependencies": {
+        "estree-walker": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
+          "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
+          "dev": true
+        }
+      }
+    },
     "router": {
       "version": "1.3.5",
       "resolved": "https://registry.npmjs.org/router/-/router-1.3.5.tgz",
@@ -39308,6 +39460,220 @@
         }
       }
     },
+    "svelte": {
+      "version": "3.31.0",
+      "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.31.0.tgz",
+      "integrity": "sha512-r+n8UJkDqoQm1b+3tA3Lh6mHXKpcfOSOuEuIo5gE2W9wQYi64RYX/qE6CZBDDsP/H4M+N426JwY7XGH4xASvGQ==",
+      "dev": true
+    },
+    "svelte-check": {
+      "version": "1.1.23",
+      "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-1.1.23.tgz",
+      "integrity": "sha512-mPIUStnwCn1PUG9Ps4shy5w46IbPXMhKigWlrfyNwV6SyDYGM+qT/DEf7+J30v47DzW3iTeR70cQu/C72IOh2g==",
+      "dev": true,
+      "requires": {
+        "chalk": "^4.0.0",
+        "chokidar": "^3.4.1",
+        "glob": "^7.1.6",
+        "import-fresh": "^3.2.1",
+        "minimist": "^1.2.5",
+        "source-map": "^0.7.3",
+        "svelte-preprocess": "^4.0.0",
+        "typescript": "*"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "anymatch": {
+          "version": "3.1.1",
+          "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
+          "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
+          "dev": true,
+          "requires": {
+            "normalize-path": "^3.0.0",
+            "picomatch": "^2.0.4"
+          }
+        },
+        "binary-extensions": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
+          "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
+          "dev": true
+        },
+        "braces": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+          "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+          "dev": true,
+          "requires": {
+            "fill-range": "^7.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "chokidar": {
+          "version": "3.4.3",
+          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz",
+          "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==",
+          "dev": true,
+          "requires": {
+            "anymatch": "~3.1.1",
+            "braces": "~3.0.2",
+            "fsevents": "~2.1.2",
+            "glob-parent": "~5.1.0",
+            "is-binary-path": "~2.1.0",
+            "is-glob": "~4.0.1",
+            "normalize-path": "~3.0.0",
+            "readdirp": "~3.5.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "fill-range": {
+          "version": "7.0.1",
+          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+          "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+          "dev": true,
+          "requires": {
+            "to-regex-range": "^5.0.1"
+          }
+        },
+        "fsevents": {
+          "version": "2.1.3",
+          "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
+          "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
+          "dev": true,
+          "optional": true
+        },
+        "glob-parent": {
+          "version": "5.1.1",
+          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
+          "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
+          "dev": true,
+          "requires": {
+            "is-glob": "^4.0.1"
+          }
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "import-fresh": {
+          "version": "3.3.0",
+          "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+          "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+          "dev": true,
+          "requires": {
+            "parent-module": "^1.0.0",
+            "resolve-from": "^4.0.0"
+          }
+        },
+        "is-binary-path": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+          "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+          "dev": true,
+          "requires": {
+            "binary-extensions": "^2.0.0"
+          }
+        },
+        "is-number": {
+          "version": "7.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+          "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+          "dev": true
+        },
+        "readdirp": {
+          "version": "3.5.0",
+          "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
+          "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
+          "dev": true,
+          "requires": {
+            "picomatch": "^2.2.1"
+          }
+        },
+        "resolve-from": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+          "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+          "dev": true
+        },
+        "source-map": {
+          "version": "0.7.3",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
+          "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        },
+        "to-regex-range": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+          "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+          "dev": true,
+          "requires": {
+            "is-number": "^7.0.0"
+          }
+        }
+      }
+    },
+    "svelte-preprocess": {
+      "version": "4.6.1",
+      "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.6.1.tgz",
+      "integrity": "sha512-s7KdhR2pOsffyOzZIMEb315f6pfgeDnOWN47m6YKFeSEx3NMf/79Znc3vuG/Ai79SL/vsi86WDrjFPLGRfDesg==",
+      "dev": true,
+      "requires": {
+        "@types/pug": "^2.0.4",
+        "@types/sass": "^1.16.0",
+        "detect-indent": "^6.0.0",
+        "strip-indent": "^3.0.0"
+      },
+      "dependencies": {
+        "detect-indent": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz",
+          "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==",
+          "dev": true
+        }
+      }
+    },
     "svgo": {
       "version": "1.3.2",
       "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz",
@@ -40723,9 +41089,9 @@
       }
     },
     "typescript": {
-      "version": "3.7.5",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz",
-      "integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==",
+      "version": "3.9.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.3.tgz",
+      "integrity": "sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ==",
       "dev": true
     },
     "ua-parser-js": {
@@ -41612,7 +41978,7 @@
         "mdast-util-inject": "1.1.0",
         "mkdirp": "0.5.1",
         "multi-glob": "^1.0.2",
-        "node-notifier": "^5.2.1",
+        "node-notifier": "^8.0.1",
         "postcss-inline-svg": "^3.1.1",
         "prismjs": "^1.17.1",
         "sass": "^1.29.0",

+ 12 - 3
package.json

@@ -67,6 +67,7 @@
     "@uppy/status-bar": "file:packages/@uppy/status-bar",
     "@uppy/store-default": "file:packages/@uppy/store-default",
     "@uppy/store-redux": "file:packages/@uppy/store-redux",
+    "@uppy/svelte": "file:packages/@uppy/svelte",
     "@uppy/thumbnail-generator": "file:packages/@uppy/thumbnail-generator",
     "@uppy/transloadit": "file:packages/@uppy/transloadit",
     "@uppy/tus": "file:packages/@uppy/tus",
@@ -96,8 +97,10 @@
     "@jamen/lorem": "0.2.0",
     "@lerna/run": "^3.21.0",
     "@octokit/rest": "16.43.1",
+    "@rollup/plugin-node-resolve": "^11.0.1",
     "@size-limit/preset-big-lib": "4.5.6",
     "@transloadit/prettier-bytes": "0.0.7",
+    "@tsconfig/svelte": "^1.0.10",
     "@types/aws-serverless-express": "3.3.3",
     "@types/compression": "1.7.0",
     "@types/connect-redis": "0.0.7",
@@ -188,10 +191,15 @@
     "replacestream": "^4.0.3",
     "resolve": "^1.17.0",
     "rimraf": "2.7.1",
+    "rollup": "^2.35.1",
+    "rollup-plugin-svelte": "^7.0.0",
     "sass": "1.29.0",
     "size-limit": "4.5.6",
     "stringify-object": "3.3.0",
     "supertest": "3.4.2",
+    "svelte": "^3.31.0",
+    "svelte-check": "^1.1.23",
+    "svelte-preprocess": "^4.6.1",
     "tar": "4.4.13",
     "temp-write": "3.4.0",
     "tinyify": "3.0.0",
@@ -199,7 +207,7 @@
     "tsd": "^0.11.0",
     "tsify": "5.0.1",
     "tus-node-server": "0.3.2",
-    "typescript": "3.7.5",
+    "typescript": "3.9.3",
     "verdaccio": "^4.8.0",
     "vue": "^2.6.12",
     "vue-template-compiler": "^2.6.11",
@@ -214,7 +222,8 @@
     "build:clean": "rm -rf packages/*/lib packages/@uppy/*/lib packages/*/dist packages/@uppy/*/dist",
     "build:companion": "cd ./packages/@uppy/companion && npm run build",
     "build:css": "node ./bin/build-css.js",
-    "build:js": "npm-run-all build:lib build:companion build:locale-pack build:bundle",
+    "build:svelte": "cd ./packages/@uppy/svelte && npm run build",
+    "build:js": "npm-run-all build:lib build:svelte build:companion build:locale-pack build:bundle",
     "build:lib": "node ./bin/build-lib.js",
     "build:locale-pack": "node ./bin/locale-packs.js build",
     "build": "npm-run-all --parallel build:js build:css --serial size",
@@ -241,7 +250,7 @@
     "test:endtoend:registry": "verdaccio --listen 4002 --config test/endtoend/verdaccio.yaml",
     "test:endtoend": "npm run test:endtoend:prepare-ci && wdio test/endtoend/wdio.remote.conf.js",
     "test:locale-packs": "node ./bin/locale-packs.js test",
-    "test:type": "lerna exec --scope '@uppy/*' --ignore '@uppy/{react-native,locales,companion,provider-views,robodog}' tsd",
+    "test:type": "lerna exec --scope '@uppy/*' --ignore '@uppy/{react-native,locales,companion,provider-views,robodog,svelte}' tsd",
     "test:unit": "npm run build:lib && jest",
     "test:watch": "jest --watch",
     "test:size": "size-limit",

+ 4 - 0
packages/@uppy/svelte/.gitignore

@@ -0,0 +1,4 @@
+.DS_Store
+node_modules
+/dist/
+package-lock.json

+ 21 - 0
packages/@uppy/svelte/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2020 Transloadit
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 30 - 0
packages/@uppy/svelte/README.md

@@ -0,0 +1,30 @@
+# @uppy/svelte
+
+<img src="https://uppy.io/images/logos/uppy-dog-head-arrow.svg" width="120" alt="Uppy logo: a superman puppy in a pink suit" align="right">
+
+<a href="https://www.npmjs.com/package/@uppy/svelte"><img src="https://img.shields.io/npm/v/@uppy/svelte.svg?style=flat-square"></a>
+<a href="https://travis-ci.org/transloadit/uppy"><img src="https://img.shields.io/travis/transloadit/uppy/master.svg?style=flat-square" alt="Build Status"></a>
+
+Svelte component wrappers around Uppy’s officially maintained UI plugins.
+
+Uppy is being developed by the folks at [Transloadit](https://transloadit.com), a versatile file encoding service.
+
+## Installation
+
+All Svelte components are provided through the `@uppy/svelte` package.
+
+Install from NPM:
+
+```shell
+npm install @uppy/svelte
+# Or with yarn
+yarn add @uppy/svelte
+```
+
+## Documentation
+
+Documentation for this plugin can be found on the [Uppy website](https://uppy.io/docs/svelte). At the moment, there is no documentation yet, so this link won't work. Stay tuned for more info
+
+## License
+
+[The MIT License](./LICENSE).

+ 32 - 0
packages/@uppy/svelte/package.json

@@ -0,0 +1,32 @@
+{
+  "name": "@uppy/svelte",
+  "svelte": "src/index.js",
+  "module": "dist/index.mjs",
+  "main": "dist/index.js",
+  "version": "0.1.0",
+  "scripts": {
+    "build": "rollup -c",
+    "prepublishOnly": "npm run build",
+    "validate": "svelte-check"
+  },
+  "dependencies": {
+    "@uppy/dashboard": "file:../dashboard",
+    "@uppy/drag-drop": "file:../drag-drop",
+    "@uppy/progress-bar": "file:../progress-bar",
+    "@uppy/status-bar": "file:../status-bar"
+  },
+  "peerDependencies": {
+    "@uppy/core": "^1.0.0",
+    "svelte": "^3.0.0"
+  },
+  "publishConfig": {
+    "access": "public"
+  },
+  "keywords": [
+    "svelte"
+  ],
+  "files": [
+    "src",
+    "dist"
+  ]
+}

+ 42 - 0
packages/@uppy/svelte/rollup.config.js

@@ -0,0 +1,42 @@
+import svelte from 'rollup-plugin-svelte'
+import resolve from '@rollup/plugin-node-resolve'
+import preprocess from 'svelte-preprocess'
+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())
+
+const globals = {
+  '@uppy/dashboard': 'Dashboard',
+  '@uppy/drag-drop': 'DragDrop',
+  '@uppy/progress-bar': 'ProgressBar',
+  '@uppy/status-bar': 'StatusBar'
+}
+
+export default {
+  input: 'src/index.js',
+  output: [
+    {
+      file: pkg.module,
+      format: 'es',
+      globals
+    },
+    {
+      file: pkg.main,
+      format: 'umd',
+      name,
+      globals
+    }
+  ],
+  plugins: [
+    svelte({
+      include: 'src/**/*.svelte',
+      preprocess: preprocess()
+    }),
+    resolve({
+      resolveOnly: ['svelte']
+    })
+  ]
+}

+ 43 - 0
packages/@uppy/svelte/src/components/Dashboard.svelte

@@ -0,0 +1,43 @@
+<script lang="ts">
+  import { onMount, onDestroy } from 'svelte'
+  import type { Uppy } from '@uppy/core';
+  import DashboardPlugin from '@uppy/dashboard'
+
+  let container: HTMLElement;
+  let plugin: DashboardPlugin;
+
+  export let uppy: Uppy;
+  export let props: Object | undefined = {};
+  export let plugins: string[] = [];
+
+  const installPlugin = () => {
+    const options = {
+      id: 'svelte:Dashboard',
+      inline: true,
+      plugins,
+      ...props,
+      target: container
+    }
+
+    uppy.use(DashboardPlugin, options);
+    plugin = uppy.getPlugin(options.id) as DashboardPlugin;
+  }
+  const uninstallPlugin = (uppyInstance: Uppy = uppy) => {
+    uppyInstance.removePlugin(plugin);
+  }
+
+  onMount(() => installPlugin())
+
+  onDestroy(() => uninstallPlugin())
+  $: {
+    const options = {
+      id: 'svelte:Dashboard',
+      inline: true,
+      plugins,
+      ...props,
+      target: container
+    }
+    uppy.setOptions(options)
+  }
+</script>
+<div bind:this={container} />

+ 54 - 0
packages/@uppy/svelte/src/components/DashboardModal.svelte

@@ -0,0 +1,54 @@
+<script lang="ts">
+  import { onMount, onDestroy } from 'svelte'
+  import type { Uppy } from '@uppy/core';
+  import DashboardPlugin from '@uppy/dashboard'
+
+  let container: HTMLElement;
+  let plugin: DashboardPlugin;
+
+  export let uppy: Uppy;
+  export let props: Object | undefined = {};
+  export let open: boolean;
+  let lastOpen: boolean = open;
+
+  export let plugins: string[] = [];
+
+  const installPlugin = () => {
+    const options = {
+      id: 'svelte:DashboardModal',
+      plugins,
+      ...props,
+      target: container
+    }
+
+    uppy.use(DashboardPlugin, options);
+    plugin = uppy.getPlugin(options.id) as DashboardPlugin;
+    if(open) plugin.openModal();
+  }
+  const uninstallPlugin = (uppyInstance: Uppy = uppy) => {
+    uppyInstance.removePlugin(plugin);
+  }
+
+  onMount(() => installPlugin())
+
+  onDestroy(() => uninstallPlugin())
+  $: {
+    const options = {
+      id: 'svelte:DashboardModal',
+      plugins,
+      ...props,
+      target: container
+    }
+    uppy.setOptions(options)
+  }
+  $: {
+    if(open && !lastOpen) {
+      plugin.openModal()
+    }
+    if (!open && lastOpen) {
+      plugin.closeModal()
+    }
+    lastOpen = open;
+  }
+</script>
+<div bind:this={container} />

+ 39 - 0
packages/@uppy/svelte/src/components/DragDrop.svelte

@@ -0,0 +1,39 @@
+<script lang="ts">
+  import { onMount, onDestroy } from 'svelte'
+  import type { Uppy, Plugin } from '@uppy/core';
+  import DragDropPlugin from '@uppy/drag-drop'
+
+  let container: HTMLElement;
+  let plugin: DragDropPlugin; 
+
+  export let uppy: Uppy;
+  export let props: Object | undefined = {};
+
+  const installPlugin = () => {
+    const options = {
+      id: 'svelte:DragDrop',
+      inline: true,
+      ...props,
+      target: container
+    }
+
+    uppy.use(DragDropPlugin, options);
+    plugin = uppy.getPlugin(options.id) as DragDropPlugin;
+  }
+  const uninstallPlugin = (uppyInstance: Uppy = uppy) => {
+    uppyInstance.removePlugin(plugin);
+  }
+
+  onMount(() => installPlugin())
+
+  onDestroy(() => uninstallPlugin())
+  $: {
+    const options = {
+      id: 'svelte:DragDrop',
+      ...props,
+      target: container
+    }
+    uppy.setOptions(options)
+  }
+</script>
+<div bind:this={container} />

+ 39 - 0
packages/@uppy/svelte/src/components/ProgressBar.svelte

@@ -0,0 +1,39 @@
+<script lang="ts">
+  import { onMount, onDestroy } from 'svelte'
+  import type { Uppy } from '@uppy/core';
+  import ProgressBarPlugin from '@uppy/progress-bar'
+
+  let container: HTMLElement;
+  let plugin: ProgressBarPlugin; 
+
+  export let uppy: Uppy;
+  export let props: Object | undefined = {};
+
+  const installPlugin = () => {
+    const options = {
+      id: 'svelte:ProgressBar',
+      inline: true,
+      ...props,
+      target: container
+    }
+
+    uppy.use(ProgressBarPlugin, options);
+    plugin = uppy.getPlugin(options.id) as ProgressBarPlugin;
+  }
+  const uninstallPlugin = (uppyInstance: Uppy = uppy) => {
+    uppyInstance.removePlugin(plugin);
+  }
+
+  onMount(() => installPlugin())
+
+  onDestroy(() => uninstallPlugin())
+  $: {
+    const options = {
+      id: 'svelte:ProgressBar',
+      ...props,
+      target: container
+    }
+    uppy.setOptions(options)
+  }
+</script>
+<div bind:this={container} />

+ 39 - 0
packages/@uppy/svelte/src/components/StatusBar.svelte

@@ -0,0 +1,39 @@
+<script lang="ts">
+  import { onMount, onDestroy } from 'svelte'
+  import type { Uppy } from '@uppy/core';
+  import StatusBarPlugin from '@uppy/status-bar'
+
+  let container: HTMLElement;
+  let plugin: StatusBarPlugin; 
+
+  export let uppy: Uppy;
+  export let props: Object | undefined = {};
+
+  const installPlugin = () => {
+    const options = {
+      id: 'svelte:StatusBar',
+      inline: true,
+      ...props,
+      target: container
+    }
+
+    uppy.use(StatusBarPlugin, options);
+    plugin = uppy.getPlugin(options.id) as StatusBarPlugin;
+  }
+  const uninstallPlugin = (uppyInstance: Uppy = uppy) => {
+    uppyInstance.removePlugin(plugin);
+  }
+
+  onMount(() => installPlugin())
+
+  onDestroy(() => uninstallPlugin())
+  $: {
+    const options = {
+      id: 'svelte:StatusBar',
+      ...props,
+      target: container
+    }
+    uppy.setOptions(options)
+  }
+</script>
+<div bind:this={container} />

+ 5 - 0
packages/@uppy/svelte/src/index.js

@@ -0,0 +1,5 @@
+export { default as Dashboard } from './components/Dashboard.svelte'
+export { default as DashboardModal } from './components/DashboardModal.svelte'
+export { default as DragDrop } from './components/DragDrop.svelte'
+export { default as ProgressBar } from './components/ProgressBar.svelte'
+export { default as StatusBar } from './components/StatusBar.svelte'

+ 13 - 0
packages/@uppy/svelte/tsconfig.json

@@ -0,0 +1,13 @@
+{
+  "extends": "@tsconfig/svelte/tsconfig.json",
+  "compilerOptions": {
+    "esModuleInterop": true,
+    "sourceMap": true
+  },
+  "include": [
+    "src/**/*"
+  ],
+  "exclude": [
+    "node_modules/*"
+  ]
+}

+ 4 - 13
packages/@uppy/vue/package.json

@@ -9,21 +9,12 @@
     "vue": ">=2.6.11"
   },
   "dependencies": {
-    "@uppy/dashboard": "1.13.1",
-    "@uppy/drag-drop": "^1.4.18",
-    "@uppy/progress-bar": "^1.3.18",
-    "@uppy/status-bar": "1.8.0",
+    "@uppy/dashboard": "file:../dashboard",
+    "@uppy/drag-drop": "file:../drag-drop",
+    "@uppy/progress-bar": "file:../progress-bar",
+    "@uppy/status-bar": "file:../status-bar",
     "shallow-equal": "^1.2.1"
   },
-  "devDependencies": {
-    "@uppy/core": "1.14.2",
-    "@uppy/dashboard": "^1.12.5",
-    "@uppy/drag-drop": "^1.4.18",
-    "@uppy/progress-bar": "^1.3.18",
-    "@uppy/status-bar": "^1.7.5",
-    "typescript": "^4.0.3",
-    "vue": "^2.6.12"
-  },
   "publishConfig": {
     "access": "public"
   }

+ 216 - 0
website/src/docs/svelte.md

@@ -0,0 +1,216 @@
+---
+title: "Svelte"
+type: docs
+module: "@uppy/svelte"
+permalink: docs/svelte/
+order: 1
+category: "Other Integrations"
+---
+
+Uppy provides [Svelte][] components for the included UI plugins.
+
+## Installation
+
+All Svelte components are provided through the `@uppy/svelte` package.
+
+Install from NPM:
+
+```shell
+npm install @uppy/svelte
+# Or with yarn
+yarn add @uppy/svelte
+```
+
+## CSS
+
+Make sure to also include the necessary CSS files for each Uppy Svelte component you are using.
+
+For [the example](https://github.com/transloadit/uppy/tree/master/examples/svelte-example), we used `svelte-preprocess` and `postcss` to allow imports in CSS. Here is a basic guide for getting that configured with Rollup.
+
+```shell
+npm install -D postcss postcss-import postcss-load-config
+# Or with yarn
+yarn add -D postcss postcss-import postcss-load-config
+```
+
+Then create a `postcss.config.js` like so:
+
+```js
+module.exports = {
+  plugins: [
+    require('postcss-import')()
+  ]
+}
+```
+
+Finally, enable `postcss` in your `rollup.config.js`
+
+```js
+import preprocess from 'svelte-preprocess'
+// ...
+svelte({
+  preprocess: preprocess({
+    postcss: true
+  })
+})
+// ...
+```
+
+## Usage
+
+The components can be used with [Svelte][] and frameworks that are based off it, like [Sapper][].
+
+Instead of adding a UI plugin to an Uppy instance with `.use()`, the Uppy instance can be passed into components as an `uppy` prop.
+
+```html
+<main> 
+  <Dashboard 
+      uppy={uppy} 
+      plugins={["Webcam"]}
+  />
+</main>
+
+<script>
+import { Dashboard } from '@uppy/svelte'
+
+import Uppy from '@uppy/core'
+import Webcam from '@uppy/webcam'
+
+let uppy = new Uppy().use(Webcam);
+</script>
+```
+
+The following plugins are available as Svelte component wrappers:
+
+- `<Dashboard />` - renders an inline `@uppy/dashboard`
+- `<DashboardModal />` - renders a `@uppy/dashboard` modal
+- `<DragDrop />` - renders a `@uppy/drag-drop` area
+- `<ProgressBar />` - renders a `@uppy/progress-bar`
+- `<StatusBar />` - renders a `@uppy/status-bar`
+
+Each component takes a `props` prop that will be passed to the UI Plugin. Both `@uppy/dashboard` based plugins also take a `plugins` array as a props, make it easy to add your plugins.
+
+### Initializing Uppy
+
+Due to the way Svelte handles reactivity, you can simply initialize Uppy the same way you would with vanilla JavaScript
+
+```js
+import Uppy from '@uppy/core'
+import Webcam from '@uppy/webcam'
+
+let uppy = new Uppy().use(Webcam)
+```
+
+## Components
+
+### `<Dashboard />`
+
+#### CSS
+
+The `Dashboard` component requires the following CSS for styling:
+
+```html
+<style global>
+@import '@uppy/core/dist/style.css';
+@import '@uppy/dashboard/dist/style.css';
+</style>
+```
+
+Import general Core styles from `@uppy/core/dist/style.css` first, then add the Dashboard styles from `@uppy/dashboard/dist/style.css`. A minified version is also available as `style.min.css` at the same path. The way to do import depends on your build system. 
+
+⚠️ The `@uppy/dashboard` plugin includes CSS for the Dashboard itself, and the various plugins used by the Dashboard, such as ([`@uppy/status-bar`](/docs/status-bar) and [`@uppy/informer`](/docs/informer)). If you also use the `@uppy/status-bar` or `@uppy/informer` plugin directly, you should not include their CSS files, but instead only use the one from the `@uppy/dashboard` plugin.
+
+Styles for Provider plugins, like Google Drive and Instagram, are also bundled with Dashboard styles. Styles for other plugins, such as `@uppy/url` and `@uppy/webcam`, are not included. If you are using those, please see their docs and make sure to include styles for them as well.
+  
+#### Props
+
+The `<Dashboard />` component supports all `@uppy/dashboard` options to be passed as an object o
+
+The `<Dashboard />` cannot be passed to a `target:` option of a remote provider or plugins such as [`@uppy/webcam`][]. To use other plugins like [`@uppy/webcam`][] with the `<Dashboard />` component, first add them to the Uppy instance, and then specify their `id` in the [`plugins`](/docs/dashboard/#plugins) prop:
+
+### `<DashboardModal />`
+
+#### CSS
+
+The `DashboardModal` component requires the following CSS for styling:
+
+```html
+<style global>
+@import '@uppy/core/dist/style.css';
+@import '@uppy/dashboard/dist/style.css';
+</style>
+```
+
+Import general Core styles from `@uppy/core/dist/style.css` first, then add the Dashboard styles from `@uppy/dashboard/dist/style.css`. A minified version is also available as `style.min.css` at the same path. The way to do import depends on your build system.
+
+⚠️ The `@uppy/dashboard` plugin includes CSS for the Dashboard itself, and the various plugins used by the Dashboard, such as ([`@uppy/status-bar`](/docs/status-bar) and [`@uppy/informer`](/docs/informer)). If you also use the `@uppy/status-bar` or `@uppy/informer` plugin directly, you should not include their CSS files, but instead only use the one from the `@uppy/dashboard` plugin.
+
+Styles for Provider plugins, like Google Drive and Instagram, are also bundled with Dashboard styles. Styles for other plugins, such as `@uppy/url` and `@uppy/webcam`, are not included. If you are using those, please see their docs and make sure to include styles for them as well.
+
+#### Props
+
+The `<DashboardModal />` component supports all `@uppy/dashboard` options to be passed as an object on the `props` prop. An Uppy instance must be provided in the `uppy={}` prop.
+
+The `<DashboardModal />` cannot be passed to a `target:` option of a remote provider or plugins such as [`@uppy/webcam`][]. To use other plugins like [`@uppy/webcam`][] with the `<DashboardModal />` component, first add them to the Uppy instance, and then specify their `id` in the [`plugins`](/docs/dashboard/#plugins) prop:
+
+### `<DragDrop />`
+
+#### CSS
+
+The `DragDrop` component includes some simple styles, like shown in the [example](/examples/dragdrop). You can also choose not to use it and provide your own styles instead:
+
+```html
+<style global>
+@import '@uppy/core/dist/style.css';
+@import '@uppy/drag-drop/dist/style.css';
+</style>
+```
+
+Import general Core styles from `@uppy/core/dist/style.css` first, then add the Drag & Drop styles from `@uppy/drag-drop/dist/style.css`. A minified version is also available as `style.min.css` at the same path. The way to do import depends on your build system.js
+
+#### Props
+
+The `<DragDrop />` component supports all `@uppy/drag-drop` options to be passed as an object on the `props` prop. An Uppy instance must be provided in the `uppy={}` prop.
+
+### `<ProgressBar />`
+
+#### CSS
+
+The `ProgressBar` plugin requires the following CSS for styling:
+
+```html
+<style global>
+@import '@uppy/core/dist/style.css';
+@import '@uppy/progress-bar/dist/style.css';
+</style>
+```
+
+Import general Core styles from `@uppy/core/dist/style.css` first, then add the Progress Bar styles from `@uppy/progress-bar/dist/style.css`. A minified version is also available as `style.min.css` at the same path. The way to do import depends on your build system.
+
+#### Props
+
+The `<ProgressBar />` component supports all `@uppy/progress-bar` options to be passed as an object on the `props` prop. An Uppy instance must be provided in the `uppy={}` prop.
+
+### `<StatusBar />`
+
+#### CSS
+
+The `StatusBar` plugin requires the following CSS for styling:
+
+```html
+<style global>
+@import '@uppy/core/dist/style.css';
+@import '@uppy/status-bar/dist/style.css';
+</style>
+```
+
+Import general Core styles from `@uppy/core/dist/style.css` first, then add the Status Bar styles from `@uppy/status-bar/dist/style.css`. A minified version is also available as `style.min.css` at the same path. The way to do import depends on your build system.
+
+#### Props
+
+The `<StatusBar />` component supports all `@uppy/status-bar` options to be passed as an object on the `props` prop. An Uppy instance must be provided in the `uppy={}` prop.
+
+[Svelte]: https://svelte.dev
+[Sapper]: https://sapper.svelte.dev
+
+[`@uppy/webcam`]: /docs/webcam/