瀏覽代碼

Merge branch 'master' into fix/uploadcdn

Renée Kooi 5 年之前
父節點
當前提交
e903340f0b
共有 57 個文件被更改,包括 2516 次插入7130 次删除
  1. 1 0
      .gitignore
  2. 29 47
      CHANGELOG.md
  3. 9 2
      examples/aws-companion/readme.md
  4. 7 0
      examples/aws-presigned-url/readme.md
  5. 7 0
      examples/custom-provider/readme.md
  6. 8 1
      examples/digitalocean-spaces/readme.md
  7. 7 0
      examples/multiple-instances/readme.md
  8. 7 1
      examples/node-xhr/readme.md
  9. 7 1
      examples/php-xhr/readme.md
  10. 7 1
      examples/python-xhr/readme.md
  11. 206 212
      examples/react-example/package-lock.json
  12. 2 2
      examples/react-example/package.json
  13. 10 0
      examples/react-native-expo/readme.md
  14. 7 0
      examples/redux/readme.md
  15. 7 0
      examples/transloadit/readme.md
  16. 12 1
      examples/uppy-with-companion/README.md
  17. 7 0
      examples/xhr-bundle/readme.md
  18. 1101 6280
      package-lock.json
  19. 7 7
      package.json
  20. 11 50
      packages/@uppy/companion/package-lock.json
  21. 1 0
      packages/@uppy/companion/package.json
  22. 29 15
      packages/@uppy/companion/src/server/Uploader.js
  23. 3 2
      packages/@uppy/companion/src/server/provider/dropbox/adapter.js
  24. 2 2
      packages/@uppy/core/src/__snapshots__/index.test.js.snap
  25. 2 2
      packages/@uppy/core/src/index.js
  26. 9 9
      packages/@uppy/core/src/index.test.js
  27. 9 0
      packages/@uppy/core/types/core-tests.ts
  28. 0 47
      packages/@uppy/dashboard/src/components/ActionBrowseTagline.js
  29. 115 79
      packages/@uppy/dashboard/src/components/AddFiles.js
  30. 16 0
      packages/@uppy/dashboard/src/index.js
  31. 11 7
      packages/@uppy/drag-drop/src/index.js
  32. 29 21
      packages/@uppy/file-input/src/index.js
  33. 1 1
      packages/@uppy/golden-retriever/src/index.js
  34. 1 24
      packages/@uppy/informer/src/index.js
  35. 148 0
      packages/@uppy/locales/src/es_GL.js
  36. 148 0
      packages/@uppy/locales/src/pt_BR.js
  37. 148 0
      packages/@uppy/locales/src/sr_RS_Latin.js
  38. 2 2
      packages/@uppy/provider-views/src/index.js
  39. 5 2
      packages/@uppy/react/src/Dashboard.d.ts
  40. 2 0
      packages/@uppy/react/src/DashboardModal.d.ts
  41. 2 2
      packages/@uppy/transloadit/src/index.test.js
  42. 1 1
      packages/@uppy/utils/src/getDroppedFiles/index.js
  43. 18 3
      packages/@uppy/utils/src/getDroppedFiles/utils/webkitGetAsEntryApi.js
  44. 1 1
      packages/@uppy/utils/types/index.d.ts
  45. 306 263
      test/endtoend/create-react-app/package-lock.json
  46. 1 1
      test/endtoend/create-react-app/package.json
  47. 14 4
      website/inject.js
  48. 15 12
      website/src/_template/list_of_locale_packs.md
  49. 1 1
      website/src/docs/aws-s3-multipart.md
  50. 2 15
      website/src/docs/informer.md
  51. 1 1
      website/src/docs/locales.md
  52. 1 1
      website/src/docs/stores.md
  53. 4 2
      website/src/docs/xhrupload.md
  54. 3 2
      website/themes/uppy/layout/index.ejs
  55. 1 1
      website/themes/uppy/layout/partials/generated_stargazers.ejs
  56. 1 1
      website/themes/uppy/layout/stats.ejs
  57. 4 1
      website/themes/uppy/source/css/_page.scss

+ 1 - 0
.gitignore

@@ -29,3 +29,4 @@ uppy-*.tgz
 output/*
 !output/.keep
 examples/dev/file.txt
+issues.txt

+ 29 - 47
CHANGELOG.md

@@ -27,23 +27,23 @@ PRs are welcome! Please do open an issue to discuss first if it's a big feature,
 - [ ] core: Add total max size to restrictions #514
 - [ ] core: consider adding presets, see https://github.com/cssinjs/jss-preset-default/blob/master/src/index.js (@arturi)
 - [ ] core: css-in-js, while keeping non-random classnames (ideally prefixed) and useful preprocessor features. also see simple https://github.com/codemirror/CodeMirror/blob/master/lib/codemirror.css (@arturi, @goto-bus-stop)
-- [ ] core: customizing metadata fields, boolean metadata; see #809, #454 and related (@arturi)
 - [ ] core: Fire event when a restriction fails #1251
 - [ ] core: good way to change plugin options at runtime—maybe `this.state.options`?
 - [ ] core: have a `resetProgress` method for resetting a single file, and call it before starting an upload. see comment in #393
 - [ ] core: Make sure Uppy works well in VR
 - [ ] core: normalize file names when uploading from iOS? $678
 - [ ] core: optimize problematic filenames #72
-- [ ] dashbaord: fix incorrectly rotated image thumbnails #472
 - [ ] dashboard: “Custom Provider” plugin for  Dashboard — shows already uploaded files or files from a custom service; accepts an array of files to show in options, no companion required #362
 - [ ] dashboard: add image cropping, study https://github.com/MattKetmo/darkroomjs/, https://github.com/fengyuanchen/cropperjs #151
 - [ ] dashboard: add option to disable uploading from local disk #657
+- [ ] dashboard: Allow custom form fields in dashboard meta editing via jsx rendering (#617, #809, #454, @arturi)
 - [ ] dashboard: allow minimizing the Dashboard during upload (Uppy then becomes just a tiny progress indicator) (@arturi)
+- [ ] dashboard: Don't hide notifications if they're hovered (https://github.com/transloadit/uppy/issues/1439)
 - [ ] dashboard: allow selecting folders (add separate hidden input button for folders) #447 #1027
 - [ ] dashboard: Consider uploading image thumbnails too #1212
 - [ ] dashboard: display data like image resolution on file cards #783
+- [ ] dashboard: fix incorrectly rotated image thumbnails #472
 - [ ] dashboard: hiding pause/resume from the UI by default (with option) would be good too probably (we could auto pause and show a resume button when detecting a network change to a metered network using https://devdocs.io/dom/networkinformation/type)
-- [ ] dashboard: if you specified a delete endpoint, the “remove/cancel upload” button remains after the upload and it not only removes, but also sends a request to that endpoint #1216
 - [ ] dashboard: possibility to edit/delete more than one file at once #118, #97
 - [ ] dashboard: possibility to work on already uploaded / in progress files #112, #113
 - [ ] dashboard: Show upload speed too if `showProgressDetails: true`. Maybe have separate options for which things are displayed, or at least have css-classes that can be hidden with `display: none` #766
@@ -61,8 +61,11 @@ PRs are welcome! Please do open an issue to discuss first if it's a big feature,
 - [ ] plugins: WordPress plugin https://www.producthunt.com/posts/uppy-io#comment-559327 (“And Gravity forms”)
 - [ ] provider: Add Facebook, OneDrive, Box
 - [ ] provider: add sorting, filtering, previews #254
-- [ ] provider: change ProviderViews signature to receive Provider instance in second param. ref https://github.com/transloadit/uppy/pull/743#discussion_r180106070
+- [ ] provider: allow consuming developers to pass in their own ProviderViews to Provider Plugins https://github.com/transloadit/uppy/issues/1143
+- [ ] provider: change ProviderViews signature to receive Provider instance in second param. (https://github.com/transloadit/uppy/pull/743#discussion_r180106070)
+- [ ] provider: MediaLibrary provider which shows you files that have already been uploaded #450, #1121, #1112
 - [ ] react: Component wrappers to manage the Uppy instance, many people initialize it in render() which does not work correctly so this could make it easier for them https://github.com/transloadit/uppy/pull/1247#issuecomment-458063951
+- [ ] core: implement a `uppy.getPlugin(x).setOptions()` method so that you can e.g. dynamically show `hideUploadButton`. we can then use this in the react component so that it rerenders appropriately. Can we also use this for changing Locales? #1193
 - [ ] rn: Uppy React Native works with Expo, now let's make it work without
 - [ ] rn: Uppy React Native works with Url Plugin, now let's make it work with Instagram
 - [ ] security: consider iframe / more security for Transloadit/Uppy integration widget and Uppy itself. Page can’t get files from Google Drive if its an iframe; possibility for folder restriction for provider plugins
@@ -83,12 +86,28 @@ PRs are welcome! Please do open an issue to discuss first if it's a big feature,
 - [ ] webcam: Webcam modes #198
 - [ ] website: automatically generated page with all locale strings used in plugins
 - [ ] website: It would be nice in the long run to have a dynamic package builder here right on the website where you can select the plugins you need/want and it builds and downloads a minified version of them? Sort of like jQuery UI: https://jqueryui.com/download/
+- [ ] xhr: allow sending custom headers per file (as proposed in #785)
+- [-] dashboard: if you specified a delete endpoint, the “remove/cancel upload” button remains after the upload and it not only removes, but also sends a request to that endpoint #1216, #832 <-- not doing this anymore because https://github.com/transloadit/uppy/pull/589#issuecomment-366754294
+
+## 2.0 
+
+- [ ] docs: Completely drop soft IE10 (and IE11?) support
+- [ ] dashboard: showing links to files should be turned off by default (it's great for devs, they can opt-in, but for end-user UI it's weird and can even lead to problems though)
+- [ ] xhr: change default name depending on wether `bundle` is set `files[]` (`true`) vs `file` (default) (#782)
+
+## 1.2
+
+- [ ] core: check option types early, like making sure `allowedFileTypes` is an array, in cases where JS would not be able to auto-fix via typecasting (otherwise it's BC-breaking)
+- [ ] dashboard: Add a Load More button so you don't have to TAB endlessly to get to the upload button (https://github.com/transloadit/uppy/issues/1419)
+- [ ] dashboard: Add Done button when upload is successfully finished (https://github.com/transloadit/uppy/issues/1510)
+- [ ] dashboard: Change select button to just say `Select 11` instead of 11 files, or folder (https://github.com/transloadit/uppy/issues/1422)
+- [ ] dashboard/dragndrop/fileinput: Add a `disabled` (`true`||`false`) option (https://github.com/transloadit/uppy/issues/1530)
+- [ ] statusbar: Add a confirmation of the cancel action (https://github.com/transloadit/uppy/issues/1418)
+- [ ] test: Switch one existing e2e test to use Parcel (create-react-app already using webpack)
 
 ## 1.1
 
 - [ ] ! core: _calculateTotalProgress results in incorrectly high (1038%) progress with files that don’t have size (like from Instagram) (@goto-bus-stop)
-- [ ] core: consider removing Preact from Plugin as pointed out on Reddit https://www.reddit.com/r/javascript/comments/bhkx5k/uppy_10_your_best_friend_in_file_uploading/
-- [x] dashboard: Remove the Authorization required tooltip on the authentication screen https://github.com/transloadit/uppy/issues/1425 (#1478 / @arturi)
 - [ ] @uppy/transloadit: finish Transloadit-Client header on https://github.com/transloadit/uppy/tree/feature/transloadit-client
 - [ ] a11y: Fix remaining issues (https://github.com/transloadit/uppy/issues/created_by/nqst)
 - [ ] chore: fix up all code using the prettier branch. work is done, just needs an execute and review/okay by the team
@@ -96,54 +115,17 @@ PRs are welcome! Please do open an issue to discuss first if it's a big feature,
 - [ ] chore: remove dead code/commented blocks
 - [ ] companion: reports an error at first sign in. we did a hotfix in https://github.com/transloadit/uppy/pull/1478#issuecomment-485937942 but need a proper fix for that (@ife). Also: what about changing the location of that tooltip? So legit errors also don't block buttons?
 - [ ] companion: restore deferredLength — parallel upload/download, 423 and 500 issues (@ife)
+- [ ] core: avoid overwriting duplicate files by a) throwing a warning instead and b) adding the relative-path of files to a new tus fingerprint function (we might use file.id as a fingerprint instead) (#754, #1606)
+- [ ] core: consider removing Preact from `Plugin` (maybe have a `(ui)Plugin extends BasePlugin`?) as pointed out on Reddit https://www.reddit.com/r/javascript/comments/bhkx5k/uppy_10_your_best_friend_in_file_uploading/
 - [ ] dashboard: add option to use `body` or `window` or CSS selector as drop zone / paste zone as well (@arturi)
 - [ ] dashboard: optional alert `onbeforeunload` while upload is in progress, safeguarding from accidentaly navigating away from a page with an ongoing upload
+- [ ] docs: Add a note to our browser support page that, while we have a saucelabs test for IE10, we're not actively supporting or fixing issues anymore (https://github.com/transloadit/uppy/issues/1420)
 - [ ] goldenretriever: make it work with aws multipart (@goto-bus-stop) https://community.transloadit.com/t/resumable-aws-s3-multipart-integration/14888
 - [ ] localepacks: Add Arabic, see if right-to-left causes issues, and fix them :)
 - [ ] meta: Clean up CHANGELOG's Backlog. Requires an Uppy call
 - [ ] meta: Turn Tim's feedback (https://app.asana.com/0/1113072057568884/1115520484178604) into actionable todos. Requires an Uppy call with Tim present
 - [ ] QA: add one integration test (or add to existing test) that uses more exotic (tus) options such as `useFastRemoteRetry` or `removeFingerprintOnSuccess` https://github.com/transloadit/uppy/issues/1327 (@arturi, @ifedapoolarewaju)
-
-
-## 1.0 Goals
-
-What we need to do to release Uppy 1.0
-
-- [x] build: (BREAKING) `npm run dev` no longer starts Companion by default, use `npm run dev:with-companion` for that (@arturi)
-- [x] chore: remove the not-working npm scripts (@kvz, @arturi)
-- [x] companion: add companion to main API service to scale it horizontally. for the standalone server, we could write the script to support multiple clusters. Not sure how required or neccessary this may be for Transloadit's API service.
-- [x] companion: better error handling, general cleanup (remove unused code. etc)
-- [x] companion: bump minor and deprecate that on npm in favour of @uppy/companion (@arturi)
-- [x] companion: rename `serverUrl` and `serverPattern` to `companionUrl` and `companionAllowedHosts` (@ifedapoolarewaju)
-- [x] companion: security audit
-- [x] companion: storing tokens in user’s browser only (d040281cc9a63060e2f2685c16de0091aee5c7b4)
-- [x] core: uppy should not crash or be slow for many files. Specifically: be able to drop 5 files (or 7mb) without the upload button to take 2 seconds to appear
-- [x] dashboard: implement Alex and Artur’s Dashboard redesign (@arturi)
-- [x] docs: on using plugins, all options, list of plugins, i18n
-- [x] feature: basic React Native support (@arturi, @ifedapoolarewaju)
-- [x] feature: beta file recovering after closed tab / browser crash
-- [x] feature: easy integration with React (UppyReact components)
-- [x] feature: finish the direct-to-s3 upload plugin and test it with the flow to then upload to :transloadit: afterwards. This is because this might influence the inner flow of the plugin architecture quite a bit
-- [x] feature: preset for Transloadit that mimics jQuery SDK, check https://github.com/transloadit/jquery-sdk docs (@goto-bus-stop)
-- [x] feature: Redux and ReduxDevTools support (currently mirrors Uppy state to Redux)
-- [x] feature: restrictions: by size, number of files, file type
-- [x] locale: cdn (just in folder like Robodog, will attach to global) / for module to all languages in one big `@uppy/locales`
-- [x] locale: update the locales of languages that we know ourselves. leave rest to community
-- [x] QA: add one integration test that uses a Provider — added Url, Google Drive/Instagram/Dropbox tests are written, but tricky to automate (@ife)
-- [x] QA: add one integration test that uses a Webpack and React/Redux environment (e.g. via `create-react-app`) (@goto-bus-stop)
-- [x] QA: make it so that all integration tests use `npm pack` and `npm install` first (@ife)
-- [x] QA: manually test in multiple browsers and mobile devices again (SauceLabs can do Android/iOS too) (@nqst)
-- [x] QA: test uppy server. benchmarks / stress test. multiple connections, different setups, large files (10 GB)
-- [x] QA: tests for core and utils
-- [x] refactoring: Make `companion` module live in main Uppy repo in `./server` as a second stage todo (after Lerna is done and we're happy) (@ife)
-- [x] refactoring: possibly switch from Yo-Yo to Preact, because it’s more stable, solves a few issues we are struggling with (onload being weird/hard/modern-browsers-only with bel; no way to pass refs to elements; extra network requests with base64 urls) and mature, “new standard”, larger community
-- [x] refactoring: split uppy into small packages, Lerna.js repo? and figure out how to share styles (during work, maybe add PR warning in `.github/*`? use `git mv` for everything) (@goto-bus-stop, @arturi)
-- [x] refactoring: webcam plugin
-- [x] transloadit: add error reporting, see https://github.com/transloadit/jquery-sdk/blob/891e99b08dd8142d8d8adc0553e6511967635ad7/js/lib/Modal.js#L122-L136 (@goto-bus-stop, @arturi)
-- [x] transloadit: should adhere cancel event and abort assembly (@goto-bus-stop)
-- [x] website: big release blog post or series
-- [x] website: design polish
-- [x] website: replace transloadit example with robodog example <-- add transloadit test key with restricted usage (no need to sign up yourself to try it)
+- [x] dashboard: Remove the Authorization required tooltip on the authentication screen https://github.com/transloadit/uppy/issues/1425 (#1478 / @arturi)
 
 ## 1.0.2
 

+ 9 - 2
examples/aws-companion/readme.md

@@ -5,9 +5,16 @@ Files are uploaded to a randomly named directory inside the `whatever/` director
 
 ## Run it
 
-First set up the `COMPANION_AWS_KEY`, `COMPANION_AWS_SECRET`, `COMPANION_AWS_REGION`, and `COMPANION_AWS_BUCKET` environment variables for @uppy/companion.
+To run this example, make sure you've correctly installed the root repository:
 
-Move into this directory, then:
+```bash
+npm install
+npm run bootstrap
+```
+
+Then, set up the `COMPANION_AWS_KEY`, `COMPANION_AWS_SECRET`, `COMPANION_AWS_REGION`, and `COMPANION_AWS_BUCKET` environment variables for @uppy/companion.
+
+Then, navigate to this directory and run:
 
 ```bash
 npm install

+ 7 - 0
examples/aws-presigned-url/readme.md

@@ -4,6 +4,13 @@ This example uses a server-side PHP endpoint to sign uploads to S3.
 
 ## Running It
 
+To run this example, make sure you've correctly installed the root repository:
+
+```bash
+npm install
+npm run bootstrap
+```
+
 This example uses the AWS PHP SDK.
 To install it, [get composer](https://getcomposer.org) and run `composer update` in this folder.
 

+ 7 - 0
examples/custom-provider/readme.md

@@ -5,6 +5,13 @@ This serves as an illustration on how integrating custom providers would work
 
 ## Run it
 
+To run this example, make sure you've correctly installed the root repository:
+
+```bash
+npm install
+npm run bootstrap
+```
+
 Move into this directory, then:
 
 ```bash

+ 8 - 1
examples/digitalocean-spaces/readme.md

@@ -2,7 +2,14 @@
 
 This example uses Uppy to upload files to a DigitolOcean Space. DigitalOcean Spaces has an identical API to S3, so we can use the [AwsS3](https://uppy.io/docs/aws-s3) plugin. We use @uppy/companion with a [custom `endpoint` configuration](./server.js#L32-L33) that points to DigitalOcean.
 
-To try this example, first run:
+To run this example, make sure you've correctly installed the root repository:
+
+```bash
+npm install
+npm run bootstrap
+```
+
+Then navigate to this directory, and run:
 
 ```bash
 npm install

+ 7 - 0
examples/multiple-instances/readme.md

@@ -5,6 +5,13 @@ It has two instances on the same page, side-by-side, but with different `id`s so
 
 ## Run it
 
+To run this example, make sure you've correctly installed the root repository:
+
+```bash
+npm install
+npm run bootstrap
+```
+
 Move into this directory, then:
 
 ```bash

+ 7 - 1
examples/node-xhr/readme.md

@@ -4,7 +4,13 @@ This example uses Node server and `@uppy/xhr-upload` to upload files to the loca
 
 ## Run it
 
-First run `npm install && npm run bootstrap && npm run build` in the root folder of the uppy project.
+To run this example, make sure you've correctly installed the root repository:
+
+```bash
+npm install
+npm run bootstrap
+npm run build
+```
 
 Then move into this directory (`examples/php-xhr`), and:
 

+ 7 - 1
examples/php-xhr/readme.md

@@ -4,7 +4,13 @@ This example uses PHP server and `@uppy/xhr-upload` to upload files to the local
 
 ## Run it
 
-First run `npm install && npm run bootstrap && npm run build` in the root folder of the uppy project.
+To run this example, make sure you've correctly installed the root repository:
+
+```bash
+npm install
+npm run bootstrap
+npm run build
+```
 
 Then move into this directory (`examples/php-xhr`), and:
 

+ 7 - 1
examples/python-xhr/readme.md

@@ -4,7 +4,13 @@ This example uses a Python Flask server and `@uppy/xhr-upload` to upload files t
 
 ## Run it
 
-First run `npm install && npm run bootstrap && npm run build` in the root folder of the uppy project.
+To run this example, make sure you've correctly installed the root repository:
+
+```bash
+npm install
+npm run bootstrap
+npm run build
+```
 
 Then move into this directory (`examples/python-xhr`), and:
 

+ 206 - 212
examples/react-example/package-lock.json

@@ -12,16 +12,16 @@
       }
     },
     "@babel/core": {
-      "version": "7.4.4",
-      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.4.tgz",
-      "integrity": "sha512-lQgGX3FPRgbz2SKmhMtYgJvVzGZrmjaF4apZ2bLwofAKiSjxU0drPh4S/VasyYXwaTs+A1gvQ45BN8SQJzHsQQ==",
+      "version": "7.4.5",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.5.tgz",
+      "integrity": "sha512-OvjIh6aqXtlsA8ujtGKfC7LYWksYSX8yQcM8Ay3LuvVeQ63lcOKgoZWVqcpFwkd29aYU9rVx7jxhfhiEDV9MZA==",
       "requires": {
         "@babel/code-frame": "^7.0.0",
         "@babel/generator": "^7.4.4",
         "@babel/helpers": "^7.4.4",
-        "@babel/parser": "^7.4.4",
+        "@babel/parser": "^7.4.5",
         "@babel/template": "^7.4.4",
-        "@babel/traverse": "^7.4.4",
+        "@babel/traverse": "^7.4.5",
         "@babel/types": "^7.4.4",
         "convert-source-map": "^1.1.0",
         "debug": "^4.1.0",
@@ -30,21 +30,6 @@
         "resolve": "^1.3.2",
         "semver": "^5.4.1",
         "source-map": "^0.5.0"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "ms": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
-          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
-        }
       }
     },
     "@babel/generator": {
@@ -120,9 +105,9 @@
       }
     },
     "@babel/parser": {
-      "version": "7.4.4",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.4.tgz",
-      "integrity": "sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w=="
+      "version": "7.4.5",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.5.tgz",
+      "integrity": "sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew=="
     },
     "@babel/plugin-syntax-jsx": {
       "version": "7.2.0",
@@ -191,34 +176,19 @@
       }
     },
     "@babel/traverse": {
-      "version": "7.4.4",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.4.tgz",
-      "integrity": "sha512-Gw6qqkw/e6AGzlyj9KnkabJX7VcubqPtkUQVAwkc0wUMldr3A/hezNB3Rc5eIvId95iSGkGIOe5hh1kMKf951A==",
+      "version": "7.4.5",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.5.tgz",
+      "integrity": "sha512-Vc+qjynwkjRmIFGxy0KYoPj4FdVDxLej89kMHFsWScq999uX+pwcX4v9mWRjW0KcAYTPAuVQl2LKP1wEVLsp+A==",
       "requires": {
         "@babel/code-frame": "^7.0.0",
         "@babel/generator": "^7.4.4",
         "@babel/helper-function-name": "^7.1.0",
         "@babel/helper-split-export-declaration": "^7.4.4",
-        "@babel/parser": "^7.4.4",
+        "@babel/parser": "^7.4.5",
         "@babel/types": "^7.4.4",
         "debug": "^4.1.0",
         "globals": "^11.1.0",
         "lodash": "^4.17.11"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "ms": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
-          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
-        }
       }
     },
     "@babel/types": {
@@ -258,13 +228,13 @@
       "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw=="
     },
     "acorn-node": {
-      "version": "1.6.2",
-      "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.6.2.tgz",
-      "integrity": "sha512-rIhNEZuNI8ibQcL7ANm/mGyPukIaZsRNX9psFNQURyJW0nu6k8wjSDld20z6v2mDBWqX13pIEnk9gGZJHIlEXg==",
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.7.0.tgz",
+      "integrity": "sha512-XhahLSsCB6X6CJbe+uNu3Mn9sJBNFxtBN9NLgAOQovfS6Kh0lDUtmlclhjn9CvEK7A7YyRU13PXlNcpSiLI9Yw==",
       "requires": {
-        "acorn": "^6.0.2",
+        "acorn": "^6.1.1",
         "acorn-dynamic-import": "^4.0.0",
-        "acorn-walk": "^6.1.0",
+        "acorn-walk": "^6.1.1",
         "xtend": "^4.0.1"
       },
       "dependencies": {
@@ -289,9 +259,9 @@
       }
     },
     "ansi-regex": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
-      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz",
+      "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk="
     },
     "ansi-styles": {
       "version": "3.2.1",
@@ -366,10 +336,11 @@
       }
     },
     "assert": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz",
-      "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=",
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz",
+      "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==",
       "requires": {
+        "object-assign": "^4.1.1",
         "util": "0.10.3"
       },
       "dependencies": {
@@ -394,9 +365,9 @@
       "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c="
     },
     "async-each": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.2.tgz",
-      "integrity": "sha512-6xrbvN0MOBKSJDdonmSSz2OwFSgxRaVtBDes26mj9KIGtDo+g9xosFRSC+i1gQh2oAN/tQ62AI/pGZGQjVOiRg=="
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
+      "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ=="
     },
     "atob": {
       "version": "2.1.2",
@@ -694,9 +665,9 @@
       }
     },
     "budo": {
-      "version": "11.6.1",
-      "resolved": "https://registry.npmjs.org/budo/-/budo-11.6.1.tgz",
-      "integrity": "sha512-Xpuw7lrxVSlfdDGU6/cDefJ/m7Y9PVh03xJrMa9/dK4Flftd6h1Skr4gL8S1UiKQqhK5odJVKyda+rFBeag3GA==",
+      "version": "11.6.2",
+      "resolved": "https://registry.npmjs.org/budo/-/budo-11.6.2.tgz",
+      "integrity": "sha512-y6rcQHf//rqY1hsVJOUXGCHD0IZyVbbzAR1Cs1CYwI/akS7A8VMDhUNU9eXdQF2kM92ogPXEDsHo5ESdv5ZwPA==",
       "requires": {
         "bole": "^2.0.0",
         "browserify": "^16.2.3",
@@ -725,7 +696,7 @@
         "subarg": "^1.0.0",
         "term-color": "^1.0.1",
         "url-trim": "^1.0.0",
-        "watchify-middleware": "^1.8.1",
+        "watchify-middleware": "^1.8.2",
         "ws": "^1.1.1",
         "xtend": "^4.0.0"
       }
@@ -791,9 +762,9 @@
       "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc="
     },
     "chokidar": {
-      "version": "2.1.5",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.5.tgz",
-      "integrity": "sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A==",
+      "version": "2.1.6",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz",
+      "integrity": "sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==",
       "requires": {
         "anymatch": "^2.0.0",
         "async-each": "^1.0.1",
@@ -880,9 +851,9 @@
       }
     },
     "component-emitter": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
-      "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+      "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
     },
     "concat-map": {
       "version": "0.0.1",
@@ -1021,11 +992,11 @@
       "integrity": "sha512-mYtLl1xfZLi1m4RtQYlZgJUNQjl4ZxVnHzIR8nLLgi4q1YT8o/WM+MK/f8yfcc9s5Ir5zRaPZyZU6xs1Syoocg=="
     },
     "debug": {
-      "version": "2.6.9",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+      "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
       "requires": {
-        "ms": "2.0.0"
+        "ms": "^2.1.1"
       }
     },
     "decode-uri-component": {
@@ -1122,13 +1093,6 @@
         "acorn-node": "^1.6.1",
         "defined": "^1.0.0",
         "minimist": "^1.1.1"
-      },
-      "dependencies": {
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
-        }
       }
     },
     "diffie-hellman": {
@@ -1245,6 +1209,14 @@
         "to-regex": "^3.0.1"
       },
       "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
         "define-property": {
           "version": "0.2.5",
           "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
@@ -1260,6 +1232,11 @@
           "requires": {
             "is-extendable": "^0.1.0"
           }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
         }
       }
     },
@@ -1419,13 +1396,13 @@
       "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
     },
     "fsevents": {
-      "version": "1.2.7",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz",
-      "integrity": "sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==",
+      "version": "1.2.9",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz",
+      "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==",
       "optional": true,
       "requires": {
-        "nan": "^2.9.2",
-        "node-pre-gyp": "^0.10.0"
+        "nan": "^2.12.1",
+        "node-pre-gyp": "^0.12.0"
       },
       "dependencies": {
         "abbrev": {
@@ -1492,11 +1469,11 @@
           "optional": true
         },
         "debug": {
-          "version": "2.6.9",
+          "version": "4.1.1",
           "bundled": true,
           "optional": true,
           "requires": {
-            "ms": "2.0.0"
+            "ms": "^2.1.1"
           }
         },
         "deep-extend": {
@@ -1628,14 +1605,6 @@
           "requires": {
             "safe-buffer": "^5.1.2",
             "yallist": "^3.0.0"
-          },
-          "dependencies": {
-            "safe-buffer": {
-              "version": "5.1.2",
-              "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-              "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
-              "optional": true
-            }
           }
         },
         "minizlib": {
@@ -1655,22 +1624,22 @@
           }
         },
         "ms": {
-          "version": "2.0.0",
+          "version": "2.1.1",
           "bundled": true,
           "optional": true
         },
         "needle": {
-          "version": "2.2.4",
+          "version": "2.3.0",
           "bundled": true,
           "optional": true,
           "requires": {
-            "debug": "^2.1.2",
+            "debug": "^4.1.0",
             "iconv-lite": "^0.4.4",
             "sax": "^1.2.4"
           }
         },
         "node-pre-gyp": {
-          "version": "0.10.3",
+          "version": "0.12.0",
           "bundled": true,
           "optional": true,
           "requires": {
@@ -1696,12 +1665,12 @@
           }
         },
         "npm-bundled": {
-          "version": "1.0.5",
+          "version": "1.0.6",
           "bundled": true,
           "optional": true
         },
         "npm-packlist": {
-          "version": "1.2.0",
+          "version": "1.4.1",
           "bundled": true,
           "optional": true,
           "requires": {
@@ -1808,7 +1777,7 @@
           }
         },
         "safe-buffer": {
-          "version": "5.1.1",
+          "version": "5.1.2",
           "bundled": true,
           "optional": true
         },
@@ -1823,7 +1792,7 @@
           "optional": true
         },
         "semver": {
-          "version": "5.6.0",
+          "version": "5.7.0",
           "bundled": true,
           "optional": true
         },
@@ -1880,14 +1849,6 @@
             "mkdirp": "^0.5.0",
             "safe-buffer": "^5.1.2",
             "yallist": "^3.0.2"
-          },
-          "dependencies": {
-            "safe-buffer": {
-              "version": "5.1.2",
-              "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-              "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
-              "optional": true
-            }
           }
         },
         "util-deprecate": {
@@ -1937,11 +1898,6 @@
         "url-trim": "^1.0.0"
       },
       "dependencies": {
-        "ansi-regex": {
-          "version": "0.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz",
-          "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk="
-        },
         "ansi-styles": {
           "version": "1.1.0",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz",
@@ -1959,19 +1915,6 @@
             "supports-color": "^0.2.0"
           }
         },
-        "has-ansi": {
-          "version": "0.1.0",
-          "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz",
-          "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=",
-          "requires": {
-            "ansi-regex": "^0.2.0"
-          }
-        },
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
-        },
         "strip-ansi": {
           "version": "0.3.0",
           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz",
@@ -2011,9 +1954,9 @@
       "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg="
     },
     "glob": {
-      "version": "7.1.3",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
-      "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+      "version": "7.1.4",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
+      "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
       "requires": {
         "fs.realpath": "^1.0.0",
         "inflight": "^1.0.4",
@@ -2043,9 +1986,9 @@
       }
     },
     "globals": {
-      "version": "11.11.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz",
-      "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw=="
+      "version": "11.12.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+      "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
     },
     "graceful-fs": {
       "version": "4.1.15",
@@ -2060,6 +2003,14 @@
         "function-bind": "^1.1.1"
       }
     },
+    "has-ansi": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz",
+      "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=",
+      "requires": {
+        "ansi-regex": "^0.2.0"
+      }
+    },
     "has-flag": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
@@ -2128,14 +2079,15 @@
       "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E="
     },
     "http-errors": {
-      "version": "1.6.3",
-      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
-      "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
+      "version": "1.7.2",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
+      "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
       "requires": {
         "depd": "~1.1.2",
         "inherits": "2.0.3",
-        "setprototypeof": "1.1.0",
-        "statuses": ">= 1.4.0 < 2"
+        "setprototypeof": "1.1.1",
+        "statuses": ">= 1.5.0 < 2",
+        "toidentifier": "1.0.0"
       }
     },
     "https-browserify": {
@@ -2391,13 +2343,6 @@
       "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==",
       "requires": {
         "minimist": "^1.2.0"
-      },
-      "dependencies": {
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
-        }
       }
     },
     "jsonify": {
@@ -2416,20 +2361,12 @@
       "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA=="
     },
     "labeled-stream-splicer": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.1.tgz",
-      "integrity": "sha512-MC94mHZRvJ3LfykJlTUipBqenZz1pacOZEMhhQ8dMGcDHs0SBE5GbsavUXV7YtP3icBW17W0Zy1I0lfASmo9Pg==",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz",
+      "integrity": "sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==",
       "requires": {
         "inherits": "^2.0.1",
-        "isarray": "^2.0.4",
         "stream-splicer": "^2.0.0"
-      },
-      "dependencies": {
-        "isarray": {
-          "version": "2.0.4",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.4.tgz",
-          "integrity": "sha512-GMxXOiUirWg1xTKRipM0Ek07rX+ubx4nNVElTJdNLYmNO/2YrDkgJGw9CljXn+r4EWiDQg/8lsRdHyg2PJuUaA=="
-        }
       }
     },
     "lodash": {
@@ -2531,9 +2468,9 @@
       }
     },
     "mime": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
-      "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ=="
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
     },
     "minimalistic-assert": {
       "version": "1.0.1",
@@ -2554,9 +2491,9 @@
       }
     },
     "minimist": {
-      "version": "0.0.8",
-      "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
-      "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+      "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
     },
     "mixin-deep": {
       "version": "1.3.1",
@@ -2583,16 +2520,23 @@
       "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
       "requires": {
         "minimist": "0.0.8"
+      },
+      "dependencies": {
+        "minimist": {
+          "version": "0.0.8",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+          "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+        }
       }
     },
     "module-deps": {
-      "version": "6.2.0",
-      "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.0.tgz",
-      "integrity": "sha512-hKPmO06so6bL/ZvqVNVqdTVO8UAYsi3tQWlCa+z9KuWhoN4KDQtb5hcqQQv58qYiDE21wIvnttZEPiDgEbpwbA==",
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.1.tgz",
+      "integrity": "sha512-UnEn6Ah36Tu4jFiBbJVUtt0h+iXqxpLqDvPS8nllbw5RZFmNJ1+Mz5BjYnM9ieH80zyxHkARGLnMIHlPK5bu6A==",
       "requires": {
         "JSONStream": "^1.0.3",
         "browser-resolve": "^1.7.0",
-        "cached-path-relative": "^1.0.0",
+        "cached-path-relative": "^1.0.2",
         "concat-stream": "~1.6.0",
         "defined": "^1.0.0",
         "detective": "^5.0.2",
@@ -2608,14 +2552,14 @@
       }
     },
     "ms": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+      "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
     },
     "nan": {
-      "version": "2.13.2",
-      "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz",
-      "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==",
+      "version": "2.14.0",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
+      "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
       "optional": true
     },
     "nanomatch": {
@@ -2818,9 +2762,9 @@
       "integrity": "sha1-VjRtR0nXjyNDDKDHE4UK75GqNh0="
     },
     "parseurl": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
-      "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
     },
     "pascalcase": {
       "version": "0.1.1",
@@ -2980,9 +2924,9 @@
       }
     },
     "range-parser": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
-      "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+      "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
     },
     "react": {
       "version": "16.8.6",
@@ -3091,9 +3035,9 @@
       "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
     },
     "resolve": {
-      "version": "1.10.0",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz",
-      "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==",
+      "version": "1.11.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz",
+      "integrity": "sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==",
       "requires": {
         "path-parse": "^1.0.6"
       }
@@ -3110,6 +3054,21 @@
       "requires": {
         "debug": "^2.2.0",
         "minimatch": "^3.0.2"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+        }
       }
     },
     "ret": {
@@ -3159,9 +3118,9 @@
       "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="
     },
     "send": {
-      "version": "0.16.2",
-      "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz",
-      "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==",
+      "version": "0.17.1",
+      "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
+      "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
       "requires": {
         "debug": "2.6.9",
         "depd": "~1.1.2",
@@ -3170,23 +3129,40 @@
         "escape-html": "~1.0.3",
         "etag": "~1.8.1",
         "fresh": "0.5.2",
-        "http-errors": "~1.6.2",
-        "mime": "1.4.1",
-        "ms": "2.0.0",
+        "http-errors": "~1.7.2",
+        "mime": "1.6.0",
+        "ms": "2.1.1",
         "on-finished": "~2.3.0",
-        "range-parser": "~1.2.0",
-        "statuses": "~1.4.0"
+        "range-parser": "~1.2.1",
+        "statuses": "~1.5.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "requires": {
+            "ms": "2.0.0"
+          },
+          "dependencies": {
+            "ms": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+              "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+            }
+          }
+        }
       }
     },
     "serve-static": {
-      "version": "1.13.2",
-      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz",
-      "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==",
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
+      "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
       "requires": {
         "encodeurl": "~1.0.2",
         "escape-html": "~1.0.3",
-        "parseurl": "~1.3.2",
-        "send": "0.16.2"
+        "parseurl": "~1.3.3",
+        "send": "0.17.1"
       }
     },
     "set-value": {
@@ -3211,9 +3187,9 @@
       }
     },
     "setprototypeof": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
-      "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+      "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
     },
     "sha.js": {
       "version": "2.4.11",
@@ -3290,6 +3266,14 @@
         "use": "^3.1.0"
       },
       "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
         "define-property": {
           "version": "0.2.5",
           "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
@@ -3305,6 +3289,11 @@
           "requires": {
             "is-extendable": "^0.1.0"
           }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
         }
       }
     },
@@ -3462,9 +3451,9 @@
       }
     },
     "statuses": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
-      "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+      "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
     },
     "stdout-stream": {
       "version": "1.4.1",
@@ -3505,9 +3494,9 @@
       }
     },
     "stream-splicer": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz",
-      "integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz",
+      "integrity": "sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==",
       "requires": {
         "inherits": "^2.0.1",
         "readable-stream": "^2.0.2"
@@ -3532,6 +3521,13 @@
       "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
       "requires": {
         "ansi-regex": "^2.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+          "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+        }
       }
     },
     "strip-eof": {
@@ -3545,13 +3541,6 @@
       "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=",
       "requires": {
         "minimist": "^1.1.0"
-      },
-      "dependencies": {
-        "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
-        }
       }
     },
     "supports-color": {
@@ -3656,6 +3645,11 @@
         "repeat-string": "^1.6.1"
       }
     },
+    "toidentifier": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+      "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
+    },
     "trim-right": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
@@ -3835,9 +3829,9 @@
       }
     },
     "watchify-middleware": {
-      "version": "1.8.1",
-      "resolved": "https://registry.npmjs.org/watchify-middleware/-/watchify-middleware-1.8.1.tgz",
-      "integrity": "sha512-wfG2byiLZwoLJ36dBWnnPCfiqMgyl+FS71+r7d6AhFSTvUzHE06+/HEbE3E7/k9REqFD3FpAOgl8qIlesaerSA==",
+      "version": "1.8.2",
+      "resolved": "https://registry.npmjs.org/watchify-middleware/-/watchify-middleware-1.8.2.tgz",
+      "integrity": "sha512-A+x5K0mHVEK2WSLOEbazcXDFnSlralMZzk364Ea39F4xFl2jGl4VQLLN5HwrnRzpF5/Ggf1Q2he0HpJtflUiHg==",
       "requires": {
         "concat-stream": "^1.5.0",
         "debounce": "^1.0.0",

+ 2 - 2
examples/react-example/package.json

@@ -11,11 +11,11 @@
     }
   },
   "dependencies": {
-    "@babel/core": "^7.4.4",
+    "@babel/core": "^7.4.5",
     "@babel/preset-react": "^7.0.0",
     "aliasify": "^2.1.0",
     "babelify": "^10.0.0",
-    "budo": "^11.6.1",
+    "budo": "^11.6.2",
     "react": "^16.8.6",
     "react-dom": "^16.8.6"
   }

+ 10 - 0
examples/react-native-expo/readme.md

@@ -6,6 +6,16 @@
 
 ## Run it
 
+To run this example, make sure you've correctly installed the root repository:
+
+```bash
+npm install
+npm run bootstrap
+npm run build
+```
+
+Then navigate to this directory and run it:
+
 ```bash
 cd examples/react-native-expo
 npm install

+ 7 - 0
examples/redux/readme.md

@@ -8,6 +8,13 @@ This example supports the [Redux Devtools extension](https://github.com/zalmoxis
 
 ## Run it
 
+To run this example, make sure you've correctly installed the root repository:
+
+```bash
+npm install
+npm run bootstrap
+```
+
 Move into this directory, then:
 
 ```bash

+ 7 - 0
examples/transloadit/readme.md

@@ -4,6 +4,13 @@ This example shows all the different Robodog APIs in action on a single page.
 
 ## Run it
 
+To run this example, make sure you've correctly installed the root repository:
+
+```bash
+npm install
+npm run bootstrap
+```
+
 Move into this directory, then:
 
 ```bash

+ 12 - 1
examples/uppy-with-companion/README.md

@@ -4,5 +4,16 @@ This is a simple, lean example that combines the usage of @uppy/companion and up
 
 ## Test it
 
-To test it, run `npm install` to install the required dependencies, and then run `npm start`
+To run this example, make sure you've correctly installed the root repository:
 
+```bash
+npm install
+npm run bootstrap
+```
+
+Then, navigate to this directory and run:
+
+```bash
+npm install
+npm start
+```

+ 7 - 0
examples/xhr-bundle/readme.md

@@ -6,6 +6,13 @@ This example uses Uppy with XHRUpload plugin in `bundle` mode. Bundle mode uploa
 
 ## Run it
 
+To run this example, make sure you've correctly installed the root repository:
+
+```bash
+npm install
+npm run bootstrap
+```
+
 Move into this directory, then:
 
 ```bash

文件差異過大導致無法顯示
+ 1101 - 6280
package-lock.json


+ 7 - 7
package.json

@@ -10,22 +10,22 @@
   "license": "MIT",
   "devDependencies": {
     "@babel/cli": "^7.4.4",
-    "@babel/core": "^7.4.4",
+    "@babel/core": "^7.4.5",
     "@babel/plugin-proposal-object-rest-spread": "^7.4.4",
     "@babel/plugin-transform-object-assign": "^7.2.0",
     "@babel/plugin-transform-proto-to-assign": "^7.4.4",
     "@babel/plugin-transform-react-jsx": "^7.3.0",
     "@babel/polyfill": "^7.4.4",
-    "@babel/preset-env": "^7.4.4",
+    "@babel/preset-env": "^7.4.5",
     "@babel/register": "^7.4.4",
     "@octokit/rest": "^16.25.0",
     "@types/react": "^16.8.10",
     "aliasify": "^2.1.0",
     "autoprefixer": "^9.5.1",
-    "babel-jest": "^24.7.1",
+    "babel-jest": "^24.8.0",
     "babelify": "^10.0.0",
     "browser-resolve": "^1.11.3",
-    "browser-sync": "^2.26.3",
+    "browser-sync": "^2.26.5",
     "browserify": "^16.2.3",
     "chai": "^4.2.0",
     "chalk": "^2.4.2",
@@ -52,8 +52,8 @@
     "isomorphic-fetch": "2.2.1",
     "jest": "^24.7.1",
     "json3": "^3.3.2",
-    "lerna": "^3.13.4",
-    "lint-staged": "^6.1.1",
+    "lerna": "^3.14.1",
+    "lint-staged": "^8.1.7",
     "minify-stream": "^1.2.0",
     "mkdirp": "0.5.1",
     "multi-glob": "^1.0.2",
@@ -78,7 +78,7 @@
     "touch": "^3.1.0",
     "tsify": "^4.0.1",
     "typescript": "^3.4.5",
-    "verdaccio": "^3.11.6",
+    "verdaccio": "^4.0.0",
     "watchify": "^3.11.1",
     "wdio-mocha-framework": "^0.6.4",
     "wdio-sauce-service": "^0.4.14",

+ 11 - 50
packages/@uppy/companion/package-lock.json

@@ -1,59 +1,20 @@
 {
 	"name": "@uppy/companion",
-	"version": "0.17.4",
+	"version": "1.0.2",
 	"lockfileVersion": 1,
 	"requires": true,
 	"dependencies": {
-		"tus-js-client": {
-			"version": "github:ifedapoolarewaju/tus-js-client#888bcf73b66698a165f086f7bbe61951597f5c1b",
-			"from": "github:ifedapoolarewaju/tus-js-client#888bcf73b66698a165f086f7bbe61951597f5c1b",
+		"mime-db": {
+			"version": "1.40.0",
+			"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
+			"integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
+		},
+		"mime-types": {
+			"version": "2.1.24",
+			"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
+			"integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
 			"requires": {
-				"buffer-from": "^0.1.1",
-				"extend": "^3.0.0",
-				"js-base64": "^2.4.9",
-				"lodash.throttle": "^4.1.1",
-				"url-parse": "^1.4.3"
-			},
-			"dependencies": {
-				"buffer-from": {
-					"version": "0.1.2",
-					"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-0.1.2.tgz",
-					"integrity": "sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg=="
-				},
-				"extend": {
-					"version": "3.0.2",
-					"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
-					"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
-				},
-				"js-base64": {
-					"version": "2.5.1",
-					"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz",
-					"integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw=="
-				},
-				"lodash.throttle": {
-					"version": "4.1.1",
-					"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
-					"integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ="
-				},
-				"querystringify": {
-					"version": "2.1.1",
-					"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz",
-					"integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA=="
-				},
-				"requires-port": {
-					"version": "1.0.0",
-					"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
-					"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
-				},
-				"url-parse": {
-					"version": "1.4.4",
-					"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz",
-					"integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==",
-					"requires": {
-						"querystringify": "^2.0.0",
-						"requires-port": "^1.0.0"
-					}
-				}
+				"mime-db": "1.40.0"
 			}
 		}
 	}

+ 1 - 0
packages/@uppy/companion/package.json

@@ -46,6 +46,7 @@
     "isobject": "3.0.1",
     "jsonwebtoken": "8.3.0",
     "lodash.merge": "4.6.1",
+    "mime-types": "2.1.24",
     "morgan": "1.9.1",
     "ms": "2.1.1",
     "node-redis-pubsub": "2.0.0",

+ 29 - 15
packages/@uppy/companion/src/server/Uploader.js

@@ -30,7 +30,6 @@ class Uploader {
    * @property {number} size
    * @property {string=} fieldname
    * @property {string} pathPrefix
-   * @property {string=} path
    * @property {any=} s3
    * @property {any} metadata
    * @property {any} uppyOptions
@@ -47,7 +46,9 @@ class Uploader {
 
     this.options = options
     this.token = uuid.v4()
-    this.options.path = `${this.options.pathPrefix}/${Uploader.FILE_NAME_PREFIX}-${this.token}`
+    this.path = `${this.options.pathPrefix}/${Uploader.FILE_NAME_PREFIX}-${this.token}`
+    this.options.metadata = this.options.metadata || {}
+    this.uploadFileName = this.options.metadata.name || path.basename(this.path)
     this.streamsEnded = false
     this.duplexStream = null
     // @TODO disabling parallel uploads and downloads for now
@@ -55,7 +56,7 @@ class Uploader {
     //   this.duplexStream = new stream.PassThrough()
     //     .on('error', (err) => logger.error(`${this.shortToken} ${err}`, 'uploader.duplex.error'))
     // }
-    this.writeStream = fs.createWriteStream(this.options.path, { mode: 0o666 }) // no executable files
+    this.writeStream = fs.createWriteStream(this.path, { mode: 0o666 }) // no executable files
       .on('error', (err) => logger.error(`${this.shortToken} ${err}`, 'uploader.write.error'))
     /** @type {number} */
     this.emittedProgress = 0
@@ -143,9 +144,9 @@ class Uploader {
   }
 
   cleanUp () {
-    fs.unlink(this.options.path, (err) => {
+    fs.unlink(this.path, (err) => {
       if (err) {
-        logger.error(`cleanup failed for: ${this.options.path} err: ${err}`, 'uploader.cleanup.error')
+        logger.error(`cleanup failed for: ${this.path} err: ${err}`, 'uploader.cleanup.error')
       }
     })
     emitter().removeAllListeners(`pause:${this.token}`)
@@ -329,10 +330,7 @@ class Uploader {
    * start the tus upload
    */
   uploadTus () {
-    const fname = path.basename(this.options.path)
-    const ftype = this.options.metadata.type
-    const metadata = Object.assign({ filename: fname, filetype: ftype }, this.options.metadata || {})
-    const file = fs.createReadStream(this.options.path)
+    const file = fs.createReadStream(this.path)
     const uploader = this
 
     // @ts-ignore
@@ -344,7 +342,14 @@ class Uploader {
       resume: true,
       retryDelays: [0, 1000, 3000, 5000],
       uploadSize: this.bytesWritten,
-      metadata,
+      metadata: Object.assign(
+        {
+          // file name and type as required by the tusd tus server
+          // https://github.com/tus/tusd/blob/5b376141903c1fd64480c06dde3dfe61d191e53d/unrouted_handler.go#L614-L646
+          filename: this.uploadFileName,
+          filetype: this.options.metadata.type
+        }, this.options.metadata
+      ),
       /**
        *
        * @param {Error} error
@@ -373,7 +378,7 @@ class Uploader {
   }
 
   uploadMultipart () {
-    const file = fs.createReadStream(this.options.path)
+    const file = fs.createReadStream(this.path)
 
     // upload progress
     let bytesUploaded = 0
@@ -385,7 +390,15 @@ class Uploader {
     const formData = Object.assign(
       {},
       this.options.metadata,
-      { [this.options.fieldname]: file }
+      {
+        [this.options.fieldname]: {
+          value: file,
+          options: {
+            filename: this.uploadFileName,
+            contentType: this.options.metadata.type
+          }
+        }
+      }
     )
     const headers = headerSanitize(this.options.headers)
     request.post({ url: this.options.endpoint, headers, formData, encoding: null }, (error, response, body) => {
@@ -425,7 +438,7 @@ class Uploader {
    * Upload the file to S3 while it is still being downloaded.
    */
   uploadS3 () {
-    const file = createTailReadStream(this.options.path, {
+    const file = createTailReadStream(this.path, {
       tail: true
     })
 
@@ -445,7 +458,7 @@ class Uploader {
       return
     }
 
-    const filename = this.options.metadata.filename || path.basename(this.options.path)
+    const filename = this.options.metadata.filename || path.basename(this.path)
     const { client, options } = this.options.s3
 
     const upload = client.upload({
@@ -467,7 +480,8 @@ class Uploader {
       if (error) {
         this.emitError(error)
       } else {
-        this.emitSuccess(null, {
+        const url = data && data.Location ? data.Location : null
+        this.emitSuccess(url, {
           response: {
             responseText: JSON.stringify(data),
             headers: {

+ 3 - 2
packages/@uppy/companion/src/server/provider/dropbox/adapter.js

@@ -1,3 +1,5 @@
+const mime = require('mime-types')
+
 exports.getUsername = (data) => {
   return data.user_email
 }
@@ -23,8 +25,7 @@ exports.getItemName = (item) => {
 }
 
 exports.getMimeType = (item) => {
-  // mime types aren't supported.
-  return null
+  return mime.lookup(exports.getItemName(item)) || null
 }
 
 exports.getItemId = (item) => {

+ 2 - 2
packages/@uppy/core/src/__snapshots__/index.test.js.snap

@@ -31,7 +31,7 @@ Object {
         "bytesUploaded": 0,
         "percentage": 0,
         "uploadComplete": false,
-        "uploadStarted": false,
+        "uploadStarted": null,
       },
       "remote": "",
       "size": null,
@@ -54,7 +54,7 @@ Object {
         "bytesUploaded": 0,
         "percentage": 0,
         "uploadComplete": false,
-        "uploadStarted": false,
+        "uploadStarted": null,
       },
       "remote": "",
       "size": null,

+ 2 - 2
packages/@uppy/core/src/index.js

@@ -221,7 +221,7 @@ class Uppy {
       percentage: 0,
       bytesUploaded: 0,
       uploadComplete: false,
-      uploadStarted: false
+      uploadStarted: null
     }
     const files = Object.assign({}, this.getState().files)
     const updatedFiles = {}
@@ -450,7 +450,7 @@ class Uppy {
         bytesUploaded: 0,
         bytesTotal: size,
         uploadComplete: false,
-        uploadStarted: false
+        uploadStarted: null
       },
       size: size,
       isRemote: isRemote,

+ 9 - 9
packages/@uppy/core/src/index.test.js

@@ -412,7 +412,7 @@ describe('src/Core', () => {
         bytesUploaded: 0,
         bytesTotal: 17175,
         uploadComplete: false,
-        uploadStarted: false,
+        uploadStarted: null,
         preprocess: { mode: 'determinate', message: 'something', value: 0 }
       })
     })
@@ -439,7 +439,7 @@ describe('src/Core', () => {
         bytesUploaded: 0,
         bytesTotal: 17175,
         uploadComplete: false,
-        uploadStarted: false
+        uploadStarted: null
       })
     })
   })
@@ -519,7 +519,7 @@ describe('src/Core', () => {
         bytesUploaded: 0,
         bytesTotal: 17175,
         uploadComplete: false,
-        uploadStarted: false,
+        uploadStarted: null,
         postprocess: { mode: 'determinate', message: 'something', value: 0 }
       })
     })
@@ -546,7 +546,7 @@ describe('src/Core', () => {
         bytesUploaded: 0,
         bytesTotal: 17175,
         uploadComplete: false,
-        uploadStarted: false
+        uploadStarted: null
       })
     })
   })
@@ -619,7 +619,7 @@ describe('src/Core', () => {
           bytesUploaded: 0,
           percentage: 0,
           uploadComplete: false,
-          uploadStarted: false
+          uploadStarted: null
         },
         remote: '',
         size: 17175,
@@ -991,7 +991,7 @@ describe('src/Core', () => {
         bytesUploaded: 12345,
         bytesTotal: 17175,
         uploadComplete: false,
-        uploadStarted: false
+        uploadStarted: null
       })
 
       core.emit('upload-progress', file, {
@@ -1003,7 +1003,7 @@ describe('src/Core', () => {
         bytesUploaded: 17175,
         bytesTotal: 17175,
         uploadComplete: false,
-        uploadStarted: false
+        uploadStarted: null
       })
     })
 
@@ -1146,14 +1146,14 @@ describe('src/Core', () => {
         bytesUploaded: 0,
         bytesTotal: 17175,
         uploadComplete: false,
-        uploadStarted: false
+        uploadStarted: null
       })
       expect(core.getFile(file2.id).progress).toEqual({
         percentage: 0,
         bytesUploaded: 0,
         bytesTotal: 17175,
         uploadComplete: false,
-        uploadStarted: false
+        uploadStarted: null
       })
       expect(core.getState().totalProgress).toEqual(0)
       expect(resetProgressEvent.mock.calls.length).toEqual(1)

+ 9 - 0
packages/@uppy/core/types/core-tests.ts

@@ -17,3 +17,12 @@ import DefaultStore = require('@uppy/store-default');
   const store = DefaultStore();
   const uppy = Uppy({ store });
 }
+
+{
+  const uppy = Uppy()
+  // this doesn't exist but type checking works anyway :)
+  const f = uppy.getFile('virtual')
+  if (f && f.progress && f.progress.uploadStarted === null) {
+    f.progress.uploadStarted = Date.now()
+  }
+}

+ 0 - 47
packages/@uppy/dashboard/src/components/ActionBrowseTagline.js

@@ -1,47 +0,0 @@
-const { h, Component } = require('preact')
-
-class ActionBrowseTagline extends Component {
-  constructor (props) {
-    super(props)
-    this.handleClick = this.handleClick.bind(this)
-  }
-
-  handleClick (ev) {
-    this.input.click()
-  }
-
-  render () {
-    const browse = (
-      <button type="button" class="uppy-Dashboard-browse" onclick={this.handleClick}>
-        {this.props.i18n('browse')}
-      </button>
-    )
-
-    // empty value="" on file input, so that the input is cleared after a file is selected,
-    // because Uppy will be handling the upload and so we can select same file
-    // after removing — otherwise browser thinks it’s already selected
-    return (
-      <div class="uppy-Dashboard-dropFilesTitle">
-        {this.props.acquirers.length === 0
-          ? this.props.i18nArray('dropPaste', { browse })
-          : this.props.i18nArray('dropPasteImport', { browse })
-        }
-        <input class="uppy-Dashboard-input"
-          hidden
-          aria-hidden="true"
-          tabindex={-1}
-          type="file"
-          name="files[]"
-          multiple={this.props.maxNumberOfFiles !== 1}
-          onchange={this.props.handleInputChange}
-          accept={this.props.allowedFileTypes}
-          value=""
-          ref={(input) => {
-            this.input = input
-          }} />
-      </div>
-    )
-  }
-}
-
-module.exports = ActionBrowseTagline

+ 115 - 79
packages/@uppy/dashboard/src/components/AddFiles.js

@@ -1,101 +1,137 @@
-const ActionBrowseTagline = require('./ActionBrowseTagline')
 const { localIcon } = require('./icons')
 const { h, Component } = require('preact')
 
-const poweredByUppy = (props) => {
-  return <a tabindex="-1" href="https://uppy.io" rel="noreferrer noopener" target="_blank" class="uppy-Dashboard-poweredBy">{props.i18n('poweredBy')} <svg aria-hidden="true" class="UppyIcon uppy-Dashboard-poweredByIcon" width="11" height="11" viewBox="0 0 11 11">
-    <path d="M7.365 10.5l-.01-4.045h2.612L5.5.806l-4.467 5.65h2.604l.01 4.044h3.718z" fill-rule="evenodd" />
-  </svg><span class="uppy-Dashboard-poweredByUppy">Uppy</span></a>
-}
 class AddFiles extends Component {
   constructor (props) {
     super(props)
-    this.handleClick = this.handleClick.bind(this)
+
+    this.triggerFileInputClick = this.triggerFileInputClick.bind(this)
+    this.handleFileInputChange = this.handleFileInputChange.bind(this)
+
+    this.renderPoweredByUppy = this.renderPoweredByUppy.bind(this)
+    this.renderHiddenFileInput = this.renderHiddenFileInput.bind(this)
+    this.renderDropPasteBrowseTagline = this.renderDropPasteBrowseTagline.bind(this)
+    this.renderMyDeviceAcquirer = this.renderMyDeviceAcquirer.bind(this)
+    this.renderAcquirer = this.renderAcquirer.bind(this)
   }
 
-  handleClick (ev) {
-    this.input.click()
+  triggerFileInputClick () {
+    this.fileInput.click()
   }
 
-  render () {
-    const hasAcquirers = this.props.acquirers.length !== 0
+  handleFileInputChange (event) {
+    this.props.handleInputChange(event)
 
-    if (!hasAcquirers) {
-      return (
-        <div class="uppy-DashboardAddFiles">
-          <div class="uppy-DashboardTabs">
-            <ActionBrowseTagline
-              acquirers={this.props.acquirers}
-              handleInputChange={this.props.handleInputChange}
-              i18n={this.props.i18n}
-              i18nArray={this.props.i18nArray}
-              allowedFileTypes={this.props.allowedFileTypes}
-              maxNumberOfFiles={this.props.maxNumberOfFiles}
-            />
-          </div>
-          <div class="uppy-DashboardAddFiles-info">
-            { this.props.note && <div class="uppy-Dashboard-note">{this.props.note}</div> }
-            { this.props.proudlyDisplayPoweredByUppy && poweredByUppy(this.props) }
-          </div>
-        </div>
-      )
-    }
+    // We clear the input after a file is selected, because otherwise
+    // change event is not fired in Chrome and Safari when a file
+    // with the same name is selected.
+    // ___Why not use value="" on <input/> instead?
+    //    Because if we use that method of clearing the input,
+    //    Chrome will not trigger change if we drop the same file twice (Issue #768).
+    event.target.value = null
+  }
+
+  renderPoweredByUppy () {
+    return (
+      <a
+        tabindex="-1"
+        href="https://uppy.io"
+        rel="noreferrer noopener"
+        target="_blank"
+        class="uppy-Dashboard-poweredBy">
+        {this.props.i18n('poweredBy') + ' '}
+        <svg aria-hidden="true" class="UppyIcon uppy-Dashboard-poweredByIcon" width="11" height="11" viewBox="0 0 11 11">
+          <path d="M7.365 10.5l-.01-4.045h2.612L5.5.806l-4.467 5.65h2.604l.01 4.044h3.718z" fill-rule="evenodd" />
+        </svg>
+        <span class="uppy-Dashboard-poweredByUppy">Uppy</span>
+      </a>
+    )
+  }
+
+  renderHiddenFileInput () {
+    return (
+      <input class="uppy-Dashboard-input"
+        hidden
+        aria-hidden="true"
+        tabindex={-1}
+        type="file"
+        name="files[]"
+        multiple={this.props.maxNumberOfFiles !== 1}
+        onchange={this.handleFileInputChange}
+        accept={this.props.allowedFileTypes}
+        ref={(ref) => { this.fileInput = ref }} />
+    )
+  }
 
-    // empty value="" on file input, so that the input is cleared after a file is selected,
-    // because Uppy will be handling the upload and so we can select same file
-    // after removing — otherwise browser thinks it’s already selected
+  renderDropPasteBrowseTagline () {
+    const browse =
+      <button type="button"
+        class="uppy-Dashboard-browse"
+        onclick={this.triggerFileInputClick}>
+        {this.props.i18n('browse')}
+      </button>
+
+    return (
+      <div class="uppy-Dashboard-dropFilesTitle">
+        {this.props.acquirers.length === 0
+          ? this.props.i18nArray('dropPaste', { browse })
+          : this.props.i18nArray('dropPasteImport', { browse })
+        }
+      </div>
+    )
+  }
+
+  renderMyDeviceAcquirer () {
+    return (
+      <div class="uppy-DashboardTab" role="presentation">
+        <button type="button"
+          class="uppy-DashboardTab-btn"
+          role="tab"
+          tabindex={0}
+          onclick={this.triggerFileInputClick}>
+          {localIcon()}
+          <div class="uppy-DashboardTab-name">{this.props.i18n('myDevice')}</div>
+        </button>
+      </div>
+    )
+  }
+
+  renderAcquirer (acquirer) {
+    return (
+      <div class="uppy-DashboardTab" role="presentation">
+        <button type="button"
+          class="uppy-DashboardTab-btn"
+          role="tab"
+          tabindex={0}
+          aria-controls={`uppy-DashboardContent-panel--${acquirer.id}`}
+          aria-selected={this.props.activePickerPanel.id === acquirer.id}
+          onclick={() => this.props.showPanel(acquirer.id)}>
+          {acquirer.icon()}
+          <div class="uppy-DashboardTab-name">{acquirer.name}</div>
+        </button>
+      </div>
+    )
+  }
+
+  render () {
     return (
       <div class="uppy-DashboardAddFiles">
+        {this.renderHiddenFileInput()}
         <div class="uppy-DashboardTabs">
-          <ActionBrowseTagline
-            acquirers={this.props.acquirers}
-            handleInputChange={this.props.handleInputChange}
-            i18n={this.props.i18n}
-            i18nArray={this.props.i18nArray}
-            allowedFileTypes={this.props.allowedFileTypes}
-            maxNumberOfFiles={this.props.maxNumberOfFiles}
-          />
-          <div class="uppy-DashboardTabs-list" role="tablist">
-            <div class="uppy-DashboardTab" role="presentation">
-              <button type="button"
-                class="uppy-DashboardTab-btn"
-                role="tab"
-                tabindex={0}
-                onclick={this.handleClick}>
-                {localIcon()}
-                <div class="uppy-DashboardTab-name">{this.props.i18n('myDevice')}</div>
-              </button>
-              <input class="uppy-Dashboard-input"
-                hidden
-                aria-hidden="true"
-                tabindex={-1}
-                type="file"
-                name="files[]"
-                multiple={this.props.maxNumberOfFiles !== 1}
-                accept={this.props.allowedFileTypes}
-                onchange={this.props.handleInputChange}
-                value=""
-                ref={(input) => { this.input = input }} />
+          {this.renderDropPasteBrowseTagline()}
+          {
+            this.props.acquirers.length > 0 &&
+            <div class="uppy-DashboardTabs-list" role="tablist">
+              {this.renderMyDeviceAcquirer()}
+              {this.props.acquirers.map((acquirer) =>
+                this.renderAcquirer(acquirer)
+              )}
             </div>
-            {this.props.acquirers.map((target) => {
-              return <div class="uppy-DashboardTab" role="presentation">
-                <button class="uppy-DashboardTab-btn"
-                  type="button"
-                  role="tab"
-                  tabindex={0}
-                  aria-controls={`uppy-DashboardContent-panel--${target.id}`}
-                  aria-selected={this.props.activePickerPanel.id === target.id}
-                  onclick={() => this.props.showPanel(target.id)}>
-                  {target.icon()}
-                  <div class="uppy-DashboardTab-name">{target.name}</div>
-                </button>
-              </div>
-            })}
-          </div>
+          }
         </div>
         <div class="uppy-DashboardAddFiles-info">
           { this.props.note && <div class="uppy-Dashboard-note">{this.props.note}</div> }
-          { this.props.proudlyDisplayPoweredByUppy && poweredByUppy(this.props) }
+          { this.props.proudlyDisplayPoweredByUppy && this.renderPoweredByUppy(this.props) }
         </div>
       </div>
     )

+ 16 - 0
packages/@uppy/dashboard/src/index.js

@@ -169,6 +169,7 @@ module.exports = class Dashboard extends Plugin {
     this.toggleFileCard = this.toggleFileCard.bind(this)
     this.toggleAddFilesPanel = this.toggleAddFilesPanel.bind(this)
     this.handlePaste = this.handlePaste.bind(this)
+    this.handlePasteOnBody = this.handlePasteOnBody.bind(this)
     this.handleInputChange = this.handleInputChange.bind(this)
     this.render = this.render.bind(this)
     this.install = this.install.bind(this)
@@ -572,12 +573,26 @@ module.exports = class Dashboard extends Plugin {
     }
 
     this.startListeningToResize()
+    document.addEventListener('paste', this.handlePasteOnBody)
 
     this.uppy.on('plugin-remove', this.removeTarget)
     this.uppy.on('file-added', this.handleFileAdded)
     this.uppy.on('complete', this.handleComplete)
   }
 
+  // ___Why do we listen to the 'paste' event on a document instead of onPaste={props.handlePaste} prop, or this.el.addEventListener('paste')?
+  //    Because (at least) Chrome doesn't handle paste if focus is on some button, e.g. 'My Device'.
+  //    => Therefore, the best option is to listen to all 'paste' events, and only react to them when we are focused on our particular Uppy instance.
+  // ___Why do we still need onPaste={props.handlePaste} for the DashboardUi?
+  //    Because if we click on the 'Drop files here' caption e.g., `document.activeElement` will be 'body'. Which means our standard determination of whether we're pasting into our Uppy instance won't work.
+  //    => Therefore, we need a traditional onPaste={props.handlePaste} handler too.
+  handlePasteOnBody (event) {
+    const isFocusInOverlay = this.el.contains(document.activeElement)
+    if (isFocusInOverlay) {
+      this.handlePaste(event)
+    }
+  }
+
   handleFileAdded () {
     this.hideAllPanels()
   }
@@ -596,6 +611,7 @@ module.exports = class Dashboard extends Plugin {
     }
 
     this.stopListeningToResize()
+    document.removeEventListener('paste', this.handlePasteOnBody)
 
     window.removeEventListener('popstate', this.handlePopState, false)
     this.uppy.off('plugin-remove', this.removeTarget)

+ 11 - 7
packages/@uppy/drag-drop/src/index.js

@@ -88,10 +88,10 @@ module.exports = class DragDrop extends Plugin {
     })
   }
 
-  handleInputChange (ev) {
+  handleInputChange (event) {
     this.uppy.log('[DragDrop] Files selected through input')
 
-    const files = toArray(ev.target.files)
+    const files = toArray(event.target.files)
 
     files.forEach((file) => {
       try {
@@ -105,6 +105,14 @@ module.exports = class DragDrop extends Plugin {
         // Nothing, restriction errors handled in Core
       }
     })
+
+    // We clear the input after a file is selected, because otherwise
+    // change event is not fired in Chrome and Safari when a file
+    // with the same name is selected.
+    // ___Why not use value="" on <input/> instead?
+    //    Because if we use that method of clearing the input,
+    //    Chrome will not trigger change if we drop the same file twice (Issue #768).
+    event.target.value = null
   }
 
   render (state) {
@@ -140,11 +148,7 @@ module.exports = class DragDrop extends Plugin {
               name={this.opts.inputName}
               multiple={restrictions.maxNumberOfFiles !== 1}
               accept={restrictions.allowedFileTypes}
-              ref={(input) => {
-                this.input = input
-              }}
-              onchange={this.handleInputChange}
-              value="" />
+              onchange={this.handleInputChange} />
             {this.i18nArray('dropHereOr', {
               browse: <span class="uppy-DragDrop-dragText">{this.i18n('browse')}</span>
             })}

+ 29 - 21
packages/@uppy/file-input/src/index.js

@@ -36,10 +36,10 @@ module.exports = class FileInput extends Plugin {
     this.handleClick = this.handleClick.bind(this)
   }
 
-  handleInputChange (ev) {
+  handleInputChange (event) {
     this.uppy.log('[FileInput] Something selected through input...')
 
-    const files = toArray(ev.target.files)
+    const files = toArray(event.target.files)
 
     files.forEach((file) => {
       try {
@@ -53,6 +53,14 @@ module.exports = class FileInput extends Plugin {
         // Nothing, restriction errors handled in Core
       }
     })
+
+    // We clear the input after a file is selected, because otherwise
+    // change event is not fired in Chrome and Safari when a file
+    // with the same name is selected.
+    // ___Why not use value="" on <input/> instead?
+    //    Because if we use that method of clearing the input,
+    //    Chrome will not trigger change if we drop the same file twice (Issue #768).
+    event.target.value = null
   }
 
   handleClick (ev) {
@@ -73,25 +81,25 @@ module.exports = class FileInput extends Plugin {
     const restrictions = this.uppy.opts.restrictions
     const accept = restrictions.allowedFileTypes ? restrictions.allowedFileTypes.join(',') : null
 
-    // empty value="" on file input, so that the input is cleared after a file is selected,
-    // because Uppy will be handling the upload and so we can select same file
-    // after removing — otherwise browser thinks it’s already selected
-    return <div class="uppy-Root uppy-FileInput-container">
-      <input class="uppy-FileInput-input"
-        style={this.opts.pretty && hiddenInputStyle}
-        type="file"
-        name={this.opts.inputName}
-        onchange={this.handleInputChange}
-        multiple={restrictions.maxNumberOfFiles !== 1}
-        accept={accept}
-        ref={(input) => { this.input = input }}
-        value="" />
-      {this.opts.pretty &&
-        <button class="uppy-FileInput-btn" type="button" onclick={this.handleClick}>
-          {this.i18n('chooseFiles')}
-        </button>
-      }
-    </div>
+    return (
+      <div class="uppy-Root uppy-FileInput-container">
+        <input class="uppy-FileInput-input"
+          style={this.opts.pretty && hiddenInputStyle}
+          type="file"
+          name={this.opts.inputName}
+          onchange={this.handleInputChange}
+          multiple={restrictions.maxNumberOfFiles !== 1}
+          accept={accept}
+          ref={(input) => { this.input = input }} />
+        {this.opts.pretty &&
+          <button class="uppy-FileInput-btn"
+            type="button"
+            onclick={this.handleClick}>
+            {this.i18n('chooseFiles')}
+          </button>
+        }
+      </div>
+    )
   }
 
   install () {

+ 1 - 1
packages/@uppy/golden-retriever/src/index.js

@@ -34,7 +34,7 @@ module.exports = class GoldenRetriever extends Plugin {
     }
     this.IndexedDBStore = new IndexedDBStore(Object.assign(
       { expires: this.opts.expires },
-      opts.indexedDB || {},
+      this.opts.indexedDB || {},
       { storeName: uppy.getID() }))
 
     this.saveFilesStateToLocalStorage = this.saveFilesStateToLocalStorage.bind(this)

+ 1 - 24
packages/@uppy/informer/src/index.js

@@ -16,26 +16,7 @@ module.exports = class Informer extends Plugin {
     this.title = 'Informer'
 
     // set default options
-    const defaultOptions = {
-      typeColors: {
-        info: {
-          text: '#fff',
-          bg: '#000'
-        },
-        warning: {
-          text: '#fff',
-          bg: '#F6A623'
-        },
-        error: {
-          text: '#fff',
-          bg: '#D32F2F'
-        },
-        success: {
-          text: '#fff',
-          bg: '#1BB240'
-        }
-      }
-    }
+    const defaultOptions = {}
 
     // merge default options with the ones set by user
     this.opts = Object.assign({}, defaultOptions, opts)
@@ -45,10 +26,6 @@ module.exports = class Informer extends Plugin {
 
   render (state) {
     const { isHidden, message, details } = state.info
-    // const style = {
-    //   backgroundColor: this.opts.typeColors[type].bg,
-    //   color: this.opts.typeColors[type].text
-    // }
 
     return (
       <div class="uppy uppy-Informer"

+ 148 - 0
packages/@uppy/locales/src/es_GL.js

@@ -0,0 +1,148 @@
+/* eslint camelcase: 0 */
+
+var es_GL = {}
+
+es_GL.strings = {
+  addMoreFiles: 'Agregar máis arquivos',
+  addingMoreFiles: 'Agregando máis arquivos',
+  allowAccessDescription: 'Para tomar fotos ou grabar video coa túa cámara, por favor permite a este sitio o acceso á cámara.',
+  allowAccessTitle: 'Por favor permite o acceso á tua cámara',
+  authenticateWith: 'Conectar a %{pluginName}',
+  authenticateWithTitle: 'Por favor autentícate con %{pluginName} para seleccionar arquivos',
+  back: 'Atrás',
+  browse: 'navegar',
+  cancel: 'Cancelar',
+  cancelUpload: 'Cancelar subida',
+  chooseFiles: 'Seleccionar arquivos',
+  closeModal: 'Pechar xanela flotante',
+  companionAuthError: 'Autorización requirida',
+  companionError: 'Conexión con Companion fallou',
+  complete: 'Completado',
+  connectedToInternet: 'Conectado a Internet',
+  copyLink: 'Copiar enlace',
+  copyLinkToClipboardFallback: 'Copia a siguiente URL',
+  copyLinkToClipboardSuccess: 'Enlace copiado ao portapapeis',
+  creatingAssembly: 'Preparando subida...',
+  creatingAssemblyFailed: 'Transloadit: Non se puido crear un Assembly',
+  dashboardTitle: 'Cargador de arquivos',
+  dashboardWindowTitle: 'Xanela para cargar arquivos (Presiona escape para cerrar)',
+  dataUploadedOfTotal: '%{complete} de %{total}',
+  done: 'Feito',
+  dropHereOr: 'Soltar arquivos aquí ou %{browse}',
+  dropHint: 'Solta os teus arqivos aquí',
+  dropPaste: 'Soltar arquivos aquí, pegar ou %{browse}',
+  dropPasteImport: 'Soltar arquivos aquí, pegar, %{browse} ou importar dende',
+  edit: 'Editar',
+  editFile: 'Editar arquivo',
+  editing: 'Editando %{file}',
+  emptyFolderAdded: 'Ningún arquivo foi agregado dende o cartafol vacía',
+  encoding: 'Codificando...',
+  enterCorrectUrl: 'URL incorrecta: Por favor asegúrate que estás ingresando un enlace a un arquivo',
+  enterUrlToImport: 'Ingresa unha URL para importar un arquivo',
+  exceedsSize: 'Este arquivo excede el tamaño máximo de',
+  failedToFetch: 'Companion non puido recuperar esta URL, por favor asegúrate que sexa correcta',
+  failedToUpload: 'Error ao subir %{file}',
+  fileSource: 'Fonte de arquivo: %{name}',
+  filesUploadedOfTotal: {
+    '0': '%{complete} de %{smart_count} arquivo subido',
+    '1': '%{complete} de %{smart_count} arquivos subidos',
+    '2': '%{complete} de %{smart_count} arquivos subidos'
+  },
+  filter: 'Filtrar',
+  finishEditingFile: 'Rematar edición de arquivo',
+  folderAdded: {
+    '0': 'Agregado %{smart_count} arquivo dende %{folder}',
+    '1': 'Agregados %{smart_count} arquivos dende %{folder}',
+    '2': 'Agregados %{smart_count} arquivos dende %{folder}'
+  },
+  import: 'Importar',
+  importFrom: 'Importar dende %{name}',
+  link: 'Enlace',
+  loading: 'Cargando...',
+  logOut: 'Pechar sesión',
+  myDevice: 'O meu Dispositivo',
+  noFilesFound: 'Non existen arquivos ou cartafol aquí',
+  noInternetConnection: 'Sin conexión a Internet',
+  pause: 'Pausar',
+  pauseUpload: 'Pausar subida',
+  paused: 'En pausa',
+  poweredBy: 'Soportado por',
+  preparingUpload: 'Preparando subida...',
+  processingXFiles: {
+    '0': 'Procesando %{smart_count} arquivo',
+    '1': 'Procesando %{smart_count} arquivos',
+    '2': 'Procesando %{smart_count} arquivos'
+  },
+  removeFile: 'Eliminar arquivo',
+  resetFilter: 'Limpar filtro',
+  resume: 'Reanudar',
+  resumeUpload: 'Reanudar subida',
+  retry: 'Intentar novamente',
+  retryUpload: 'Intentar subida novamente',
+  saveChanges: 'Gardar cambios',
+  selectXFiles: {
+    '0': 'Seleccionar %{smart_count} arquivo',
+    '1': 'Seleccionar %{smart_count} arquivos',
+    '2': 'Seleccionar %{smart_count} arquivos'
+  },
+  smile: 'Sorrí!',
+  startRecording: 'Comezar a grabación de vídeo',
+  stopRecording: 'Detener la grabación de vídeo',
+  takePicture: 'Tomar unha foto',
+  timedOut: 'Subida estancada por %{seconds} segundos, anulando.',
+  upload: 'Subir',
+  uploadComplete: 'Subida rematada',
+  uploadFailed: 'A subida fallou',
+  uploadPaused: 'Subida pausada',
+  uploadXFiles: {
+    '0': 'Subir %{smart_count} arquivo',
+    '1': 'Subir %{smart_count} arquivos',
+    '2': 'Subir %{smart_count} arquivos'
+  },
+  uploadXNewFiles: {
+    '0': 'Subir +%{smart_count} arquivo',
+    '1': 'Subir +%{smart_count} arquivos',
+    '2': 'Subir +%{smart_count} arquivos'
+  },
+  uploading: 'Subiendo',
+  uploadingXFiles: {
+    '0': 'Subindo %{smart_count} arquivo',
+    '1': 'Subindo %{smart_count} arquivos',
+    '2': 'Subindo %{smart_count} arquivos'
+  },
+  xFilesSelected: {
+    '0': '%{smart_count} arquivo seleccionado',
+    '1': '%{smart_count} arquivos seleccionados',
+    '2': '%{smart_count} arquivos seleccionados'
+  },
+  xMoreFilesAdded: {
+    '0': '%{smart_count} arquivo máis agregado',
+    '1': '%{smart_count} arquivos máis agregados',
+    '2': '%{smart_count} arquivos máis agregados'
+  },
+  xTimeLeft: '%{time} restantes',
+  youCanOnlyUploadFileTypes: 'Soamente podes subir: %{types}',
+  youCanOnlyUploadX: {
+    '0': 'Soamente podes subir %{smart_count} arquivo',
+    '1': 'Soamente podes subir %{smart_count} arquivos',
+    '2': 'Soamente podes subir %{smart_count} arquivos'
+  },
+  youHaveToAtLeastSelectX: {
+    '0': 'Tes que seleccionar polo menos %{smart_count} arquivo',
+    '1': 'Tes que seleccionar polo menos %{smart_count} arquivos',
+    '2': 'Tes que seleccionar polo menos %{smart_count} arquivos'
+  }
+}
+
+es_GL.pluralize = function (n) {
+  if (n === 1) {
+    return 0
+  }
+  return 1
+}
+
+if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
+  window.Uppy.locales.es_GL = es_GL
+}
+
+module.exports = es_GL

+ 148 - 0
packages/@uppy/locales/src/pt_BR.js

@@ -0,0 +1,148 @@
+/* eslint camelcase: 0 */
+
+const pt_BR = {}
+
+pt_BR.strings = {
+  addMoreFiles: 'Adicionar mais arquivos',
+  addingMoreFiles: 'Adicionando mais arquivos',
+  allowAccessDescription: 'Para poder tirar fotos e gravar vídeos com sua câmera, por favor permita o acesso a câmera para esse site.',
+  allowAccessTitle: 'Por favor permita o acesso a sua câmera',
+  authenticateWith: 'Conectar com %{pluginName}',
+  authenticateWithTitle: 'Por favor conecte com %{pluginName} para selecionar arquivos',
+  back: 'Voltar',
+  browse: 'navegue',
+  cancel: 'Cancelar',
+  cancelUpload: 'Cancelar envio de arquivos',
+  chooseFiles: 'Selecionar arquivos',
+  closeModal: 'Fechar Modal',
+  companionAuthError: 'Autorização necessária',
+  companionError: 'Conexão com serviço falhou',
+  complete: 'Concluído',
+  connectedToInternet: 'Conectado á internet',
+  copyLink: 'Copiar link',
+  copyLinkToClipboardFallback: 'Copiar URL abaixo',
+  copyLinkToClipboardSuccess: 'Link copiado para a área de transferência',
+  creatingAssembly: 'Preparando envio de arquivos...',
+  creatingAssemblyFailed: 'Transloadit: Não foi possível criar o Assembly',
+  dashboardTitle: 'Envio de arquivos',
+  dashboardWindowTitle: 'Janela para envio de arquivos (Pressione esc para fechar)',
+  dataUploadedOfTotal: '%{complete} de %{total}',
+  done: 'Concluir',
+  dropHereOr: 'Arraste arquivos aqui ou %{browse}',
+  dropHint: 'Solte seus arquivos aqui',
+  dropPaste: 'Solte arquivos aqui, cole ou %{browse}',
+  dropPasteImport: 'Solte arquivos aqui, cole, %{browse} ou importe de',
+  edit: 'Editar',
+  editFile: 'Editar arquivo',
+  editing: 'Editando %{file}',
+  emptyFolderAdded: 'Nenhum arquivo foi adicionado da pasta vazia',
+  encoding: 'Codificando...',
+  enterCorrectUrl: 'URL incorreta: Por favor tenha certeza que inseriu um link direto para um arquivo',
+  enterUrlToImport: 'Coloque a URL para importar um arquivo',
+  exceedsSize: 'Esse arquivo excedeu o tamanho máximo permitido',
+  failedToFetch: 'Serviço falgou para buscar essa URL, por favor tenha certeza que a URL está correta',
+  failedToUpload: 'Falha para enviar %{file}',
+  fileSource: 'Origem do arquivo: %{name}',
+  filesUploadedOfTotal: {
+    '0': '%{complete} de %{smart_count} arquivo enviado',
+    '1': '%{complete} de %{smart_count} arquivos enviados',
+    '2': '%{complete} de %{smart_count} arquivos enviados'
+  },
+  filter: 'Filtrar',
+  finishEditingFile: 'Finalizar edição de arquivo',
+  folderAdded: {
+    '0': 'Adicionado %{smart_count} arquivo de %{folder}',
+    '1': 'Adicionado %{smart_count} arquivos de %{folder}',
+    '2': 'Adicionado %{smart_count} arquivos de %{folder}'
+  },
+  import: 'Importar',
+  importFrom: 'Importar de %{name}',
+  link: 'Link',
+  loading: 'Carregando...',
+  logOut: 'Deslogar',
+  myDevice: 'Meu dispositivo',
+  noFilesFound: 'Você não possui arquivos ou pastas aqui',
+  noInternetConnection: 'Sem conexão com a internet',
+  pause: 'Pausar',
+  pauseUpload: 'Pausar envio de arquivos',
+  paused: 'Pausado',
+  poweredBy: 'Desenvolvido por',
+  preparingUpload: 'Preparando envio de arquivos...',
+  processingXFiles: {
+    '0': 'Processando %{smart_count} arquivo',
+    '1': 'Processando %{smart_count} arquivos',
+    '2': 'Processando %{smart_count} arquivos'
+  },
+  removeFile: 'Remover arquivo',
+  resetFilter: 'Resetar filtro',
+  resume: 'Retomar',
+  resumeUpload: 'Retomar envio de arquivos',
+  retry: 'Tentar novamente',
+  retryUpload: 'Tentar enviar novamente',
+  saveChanges: 'Salvar alterações',
+  selectXFiles: {
+    '0': 'Selecionar %{smart_count} arquivo',
+    '1': 'Selecionar %{smart_count} arquivo',
+    '2': 'Selecionar %{smart_count} arquivos'
+  },
+  smile: 'Sorria!',
+  startRecording: 'Começar gravação de vídeo',
+  stopRecording: 'Parar gravação de vídeo',
+  takePicture: 'Tirar uma foto',
+  timedOut: 'Envio de arquivos parado por %{seconds} segundos, abortando.',
+  upload: 'Enviar arquivos',
+  uploadComplete: 'Envio de arquivos finalizado',
+  uploadFailed: 'Envio de arquivos falhou',
+  uploadPaused: 'Envio de arquivos pausado',
+  uploadXFiles: {
+    '0': 'Enviar %{smart_count} arquivo',
+    '1': 'Enviar %{smart_count} arquivo',
+    '2': 'Enviar %{smart_count} arquivos'
+  },
+  uploadXNewFiles: {
+    '0': 'Enviar +%{smart_count} arquivo',
+    '1': 'Enviar +%{smart_count} arquivos',
+    '2': 'Enviar +%{smart_count} arquivos'
+  },
+  uploading: 'Enviando',
+  uploadingXFiles: {
+    '0': 'Enviando %{smart_count} arquivo',
+    '1': 'Enviando %{smart_count} arquivos',
+    '2': 'Enviando %{smart_count} arquivos'
+  },
+  xFilesSelected: {
+    '0': '%{smart_count} arquivo selecionado',
+    '1': '%{smart_count} arquivos selecionados',
+    '2': '%{smart_count} arquivos selecionados'
+  },
+  xMoreFilesAdded: {
+    '0': '%{smart_count} arquivo adicionados',
+    '1': '%{smart_count} arquivos adicionados',
+    '2': '%{smart_count} arquivos adicionados'
+  },
+  xTimeLeft: '%{time} restantes',
+  youCanOnlyUploadFileTypes: 'Você pode enviar apenas aquivos: %{types}',
+  youCanOnlyUploadX: {
+    '0': 'Você pode enviar apenas %{smart_count} arquivo',
+    '1': 'Você pode enviar apenas %{smart_count} arquivos',
+    '2': 'Você pode enviar apenas %{smart_count} arquivos'
+  },
+  youHaveToAtLeastSelectX: {
+    '0': 'Você precisa selecionar pelo menos %{smart_count} arquivo',
+    '1': 'Você precisa selecionar pelo menos %{smart_count} arquivos',
+    '2': 'Você precisa selecionar pelo menos %{smart_count} arquivos'
+  }
+}
+
+pt_BR.pluralize = function (n) {
+  if (n === 1) {
+    return 0
+  }
+  return 1
+}
+
+if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
+  window.Uppy.locales.pt_BR = pt_BR
+}
+
+module.exports = pt_BR

+ 148 - 0
packages/@uppy/locales/src/sr_RS_Latin.js

@@ -0,0 +1,148 @@
+/* eslint camelcase: 0 */
+
+const sr_RS_Latin = {}
+
+sr_RS_Latin.strings = {
+  addMoreFiles: 'Dodaj još datoteka',
+  addingMoreFiles: 'Dodavanje datoteka',
+  allowAccessDescription: 'Molimo Vas, dozvolite pristup Vašoj kameri, kako biste mogli da je koristite za snimanje fotografija i video zapisa.',
+  allowAccessTitle: 'Molimo Vas, dozvolite pristup Vašoj kameri',
+  authenticateWith: 'Poveži se putem %{pluginName}',
+  authenticateWithTitle: 'Molimo Vas da se prijavite putem %{pluginName} kako biste preuzeli datoteke',
+  back: 'Nazad',
+  browse: 'potraži',
+  cancel: 'Otkaži',
+  cancelUpload: 'Otkaži otpremanje',
+  chooseFiles: 'Izaberi datoteke',
+  closeModal: 'Zatvori',
+  companionAuthError: 'Neophodna je provera ovlašćenja',
+  companionError: 'Neuspelo povezivanje sa Companion',
+  complete: 'Otpremljeno',
+  connectedToInternet: 'Povezan na internet',
+  copyLink: 'Sastavi link',
+  copyLinkToClipboardFallback: 'Kopiraj (sačuvaj) donji URL',
+  copyLinkToClipboardSuccess: 'Link je kopiran u klipbord',
+  creatingAssembly: 'Pripremanje otpremanja...',
+  creatingAssemblyFailed: 'Transloadit: ne mogu da napravim Assembly',
+  dashboardTitle: 'Otpremanje datoteka',
+  dashboardWindowTitle: 'Prozor za otpremanje datoteka (pritirnite ESC za izlaz)',
+  dataUploadedOfTotal: '%{complete} od %{total}',
+  done: 'Završeno',
+  dropHereOr: 'Spusti datoteke ovde ili %{browse}',
+  dropHint: 'Spusti datoteke ovde',
+  dropPaste: 'Spusti datoteke ovde, umetni ili %{browse}',
+  dropPasteImport: 'Spusti datoteke ovde, umetni (eng. "paste"), %{browse} ili preuzmi sa',
+  edit: 'Izmeni',
+  editFile: 'Izmeni datoteku',
+  editing: 'Menjanje %{file}',
+  emptyFolderAdded: 'Ni jedna datoteka nije dodata iz praznog direktorijuma',
+  encoding: 'Šifrovanje...',
+  enterCorrectUrl: 'Pogrešan URL: unesite tačnu putanju do datoteke',
+  enterUrlToImport: 'Unesite URL (putanju) do datoteke',
+  exceedsSize: 'Ova datoteka premašuje najveću dozvoljenu veličinu od',
+  failedToFetch: 'Companion nije uspeo da dopre do date adrese (URL), proverite ispravnost adrese',
+  failedToUpload: 'Broj neuspelo otpremljenih datoteka: %{file}',
+  fileSource: 'Datoteka: %{name}',
+  filesUploadedOfTotal: {
+    '0': '%{complete}. Ukupno otremljenih datoteka: %{smart_count}',
+    '1': '%{complete}. Ukupno otremljenih datoteka: %{smart_count}',
+    '2': '%{complete}. Ukupno otremljenih datoteka: %{smart_count}'
+  },
+  filter: 'Filter',
+  finishEditingFile: 'Završi menjanje fajla',
+  folderAdded: {
+    '0': 'Broj datoteka preuzetih iz %{folder}: %{smart_count}',
+    '1': 'Broj datoteka preuzetih iz %{folder}: %{smart_count}',
+    '2': 'Broj datoteka preuzetih iz %{folder}: %{smart_count}'
+  },
+  import: 'Preuzmi',
+  importFrom: 'Preuzmi sa %{name}',
+  link: 'Link',
+  loading: 'Učitavam...',
+  logOut: 'Odjava',
+  myDevice: 'Moj računar ili mobilni uređaj',
+  noFilesFound: 'Ovde nema foldera ili datoteka',
+  noInternetConnection: 'Nema veze sa internetom',
+  pause: 'Zaustavi privremeno',
+  pauseUpload: 'Privremeno zaustavi otpremanje',
+  paused: 'Privremeno zaustavljeno',
+  poweredBy: 'Otpremanje pokreće',
+  preparingUpload: 'Pripremam otpremanje...',
+  processingXFiles: {
+    '0': 'Obrada datoteke',
+    '1': 'Broj datoteka koje se obrađuju: %{smart_count}',
+    '2': 'Broj datoteka koje se obrađuju: %{smart_count}'
+  },
+  removeFile: 'Ukloni dadoteku',
+  resetFilter: 'Izbriši filter',
+  resume: 'Nastavi',
+  resumeUpload: 'Nastavi otpremanje',
+  retry: 'Pokušaj ponovo',
+  retryUpload: 'Pokušaj ponovo da otpremiš',
+  saveChanges: 'Sačuvaj izmene',
+  selectXFiles: {
+    '0': 'Izaberi datoteku',
+    '1': 'Izaberi %{smart_count} datoteke',
+    '2': 'Izaberi %{smart_count} datoteka'
+  },
+  smile: 'Osmeh!',
+  startRecording: 'Započni snimanje video zapisa',
+  stopRecording: 'Zaustavi snimanje video zapisa',
+  takePicture: 'Snimi fotografiju',
+  timedOut: 'Prekidamo otpremanje jer je zastalo. Broj sekundi zastoja: %{seconds}.',
+  upload: 'Otpremi',
+  uploadComplete: 'Otpremanje je završeno u celosti',
+  uploadFailed: 'Otpremanje nije uspelo',
+  uploadPaused: 'Otpremanje je privremeno zaustavljeno',
+  uploadXFiles: {
+    '0': 'Otpremi datoteku',
+    '1': 'Otpremi datoteke. Ukupno: %{smart_count}',
+    '2': 'Otpremi datoteke. Ukupno: %{smart_count}'
+  },
+  uploadXNewFiles: {
+    '0': 'Otpremi +%{smart_count} datoteku',
+    '1': 'Otpremi datoteke. Ukupno: +%{smart_count}',
+    '2': 'Otpremi datoteke. Ukupno: +%{smart_count}'
+  },
+  uploading: 'Otpremanje',
+  uploadingXFiles: {
+    '0': 'Broj datoteka koje se trenutno otpremaju: %{smart_count}',
+    '1': 'Broj datoteka koje se trenutno otpremaju: %{smart_count}',
+    '2': 'Broj datoteka koje se trenutno otpremaju: %{smart_count}'
+  },
+  xFilesSelected: {
+    '0': 'Broj datoteka za otpremanje: %{smart_count}',
+    '1': 'Broj datoteka za otpremanje: %{smart_count}',
+    '2': 'Broj datoteka za otpremanje: %{smart_count}'
+  },
+  xMoreFilesAdded: {
+    '0': 'Broj dodatih datoteka: %{smart_count}',
+    '1': 'Broj dodatih datoteka: %{smart_count}',
+    '2': 'Broj dodatih datoteka: %{smart_count}'
+  },
+  xTimeLeft: 'Preostalo vreme %{time} ',
+  youCanOnlyUploadFileTypes: 'Možete da otpremite samo: %{types}',
+  youCanOnlyUploadX: {
+    '0': 'Dozvoljeni broj datoteka za otpremanje: %{smart_count}',
+    '1': 'Dozvoljeni broj datoteka za otpremanje: %{smart_count}',
+    '2': 'Dozvoljeni broj datoteka za otpremanje: %{smart_count}'
+  },
+  youHaveToAtLeastSelectX: {
+    '0': 'Izaberite bar jednu datoteku',
+    '1': 'Izaberite datoteke. Najmanje: %{smart_count}',
+    '2': 'Izaberite datoteke. Najmanje: %{smart_count}'
+  }
+}
+
+sr_RS_Latin.pluralize = function (n) {
+  if (n === 1) {
+    return 0
+  }
+  return 1
+}
+
+if (typeof window !== 'undefined' && typeof window.Uppy !== 'undefined') {
+  window.Uppy.locales.sr_RS_Latin = sr_RS_Latin
+}
+
+module.exports = sr_RS_Latin

+ 2 - 2
packages/@uppy/provider-views/src/index.js

@@ -458,8 +458,8 @@ module.exports = class ProviderView {
 
     const patterns = Array.isArray(allowedOrigin) ? allowedOrigin.map(getRegex) : [getRegex(allowedOrigin)]
     return patterns
-      .filter((pattern) => pattern !== null)
-      .some((pattern) => pattern.test(origin))
+      .filter((pattern) => pattern != null) // loose comparison to catch undefined
+      .some((pattern) => pattern.test(origin) || pattern.test(`${origin}/`)) // allowing for trailing '/'
   }
 
   handleError (error) {

+ 5 - 2
packages/@uppy/react/src/Dashboard.d.ts

@@ -13,11 +13,14 @@ export interface DashboardProps {
   trigger?: string;
   width?: number;
   height?: number;
-  showProgressDetails?: boolean;
   showLinkToFileUploadResult?: boolean;
-  showSelectedFiles?: boolean;
+  showProgressDetails?: boolean;
   hideUploadButton?: boolean;
+  hideRetryButton?: boolean;
+  hidePauseResumeButton?: boolean;
+  hideCancelButton?: boolean;
   hideProgressAfterFinish?: boolean;
+  showSelectedFiles?: boolean;
   note?: string;
   metaFields?: Array<MetaField>;
   proudlyDisplayPoweredByUppy?: boolean;

+ 2 - 0
packages/@uppy/react/src/DashboardModal.d.ts

@@ -4,6 +4,8 @@ export interface DashboardModalProps extends DashboardProps {
   target?: string | HTMLElement;
   open?: boolean;
   onRequestClose?: VoidFunction;
+  closeAfterFinish?: boolean;
+  animateOpenClose?: boolean;
   closeModalOnClickOutside?: boolean;
   disablePageScrollWhenModalOpen?: boolean;
 }

+ 2 - 2
packages/@uppy/transloadit/src/index.test.js

@@ -51,7 +51,7 @@ describe('Transloadit', () => {
       const fileID = Object.keys(uppy.getState().files)[0]
 
       expect(err.message).toBe('Failure!')
-      expect(uppy.getFile(fileID).progress.uploadStarted).toBe(false)
+      expect(uppy.getFile(fileID).progress.uploadStarted).toBe(null)
     })
   })
 
@@ -79,7 +79,7 @@ describe('Transloadit', () => {
       const fileID = Object.keys(uppy.getState().files)[0]
 
       expect(err.message).toBe('Transloadit: Could not create Assembly: VIDEO_ENCODE_VALIDATION')
-      expect(uppy.getFile(fileID).progress.uploadStarted).toBe(false)
+      expect(uppy.getFile(fileID).progress.uploadStarted).toBe(null)
     })
   })
 })

+ 1 - 1
packages/@uppy/utils/src/getDroppedFiles/index.js

@@ -8,7 +8,7 @@ const fallbackApi = require('./utils/fallbackApi')
 // @returns {Promise} - Array<File>
 module.exports = function getDroppedFiles (dataTransfer) {
   // Get all files from all subdirs. Works (at least) in Chrome, Mozilla, and Safari
-  if (dataTransfer.items[0] && 'webkitGetAsEntry' in dataTransfer.items[0]) {
+  if (dataTransfer.items && dataTransfer.items[0] && 'webkitGetAsEntry' in dataTransfer.items[0]) {
     return webkitGetAsEntryApi(dataTransfer)
   // Otherwise just return all first-order files
   } else {

+ 18 - 3
packages/@uppy/utils/src/getDroppedFiles/utils/webkitGetAsEntryApi.js

@@ -1,5 +1,22 @@
 const toArray = require('../../toArray')
 
+/**
+ * Get the relative path from the FileEntry#fullPath, because File#webkitRelativePath is always '', at least onDrop.
+ *
+ * @param {FileEntry} fileEntry
+ *
+ * @return {string|null} - if file is not in a folder - return null (this is to be consistent with .relativePath-s of files selected from My Device). If file is in a folder - return its fullPath, e.g. '/simpsons/hi.jpeg'.
+ */
+function getRelativePath (fileEntry) {
+  // fileEntry.fullPath - "/simpsons/hi.jpeg" or undefined (for browsers that don't support it)
+  // fileEntry.name - "hi.jpeg"
+  if (!fileEntry.fullPath || fileEntry.fullPath === '/' + fileEntry.name) {
+    return null
+  } else {
+    return fileEntry.fullPath
+  }
+}
+
 // Recursive function, calls the original callback() when the directory is entirely parsed.
 // @param {function} callback - called with ([ all files and directories in that directoryReader ])
 function readEntries (directoryReader, oldEntries, callback) {
@@ -29,9 +46,7 @@ function addEntryToFiles (resolve, files, fileEntry) {
   // Creates a new File object which can be used to read the file.
   fileEntry.file(
     (file) => {
-      // Preserve the relative path from the FileSystemFileEntry#fullPath, because File#webkitRelativePath is always '', at least onDrop.
-      // => "/docs/Prague/ticket_from_prague_to_ufa.pdf"
-      file.relativePath = fileEntry.fullPath
+      file.relativePath = getRelativePath(fileEntry)
       files.push(file)
       resolve()
     },

+ 1 - 1
packages/@uppy/utils/types/index.d.ts

@@ -148,7 +148,7 @@ declare module '@uppy/utils' {
     name: string;
     preview?: string;
     progress?: {
-      uploadStarted: number;
+      uploadStarted: number | null;
       uploadComplete: boolean;
       percentage: number;
       bytesUploaded: number;

文件差異過大導致無法顯示
+ 306 - 263
test/endtoend/create-react-app/package-lock.json


+ 1 - 1
test/endtoend/create-react-app/package.json

@@ -7,7 +7,7 @@
     "es6-shim": "^0.35.3",
     "react": "^16.8.6",
     "react-dom": "^16.8.6",
-    "react-scripts": "3.0.0"
+    "react-scripts": "3.0.1"
   },
   "scripts": {
     "start": "react-scripts start",

+ 14 - 4
website/inject.js

@@ -179,7 +179,7 @@ async function injectMarkdown () {
 function injectLocaleList () {
   const mdTable = [
     `<!-- WARNING! This file was automatically injected. Please run "${path.basename(__filename)}" to re-generate -->\n\n`,
-    '| Language        | NPM                | CDN                 | Source on GitHub |',
+    '| %count% Locales | NPM                | CDN                 | Source on GitHub |',
     '| --------------- | ------------------ | ------------------- | ---------------- |'
   ]
   const mdRows = []
@@ -189,17 +189,27 @@ function injectLocaleList () {
 
   glob.sync(localePackagePath).forEach((localePath) => {
     const localeName = path.basename(localePath, '.js')
-    const localeNameWithDash = localeName.replace('_', '-')
+    let localeNameWithDash = localeName.replace(/_/g, '-')
+
+    const parts = localeNameWithDash.split('-')
+    let variant = ''
+    if (parts.length > 2) {
+      let lang = parts.shift()
+      let country = parts.shift()
+      variant = parts.join(', ')
+      localeNameWithDash = `${lang}-${country}`
+    }
+
     const languageName = LocaleCode.getLanguageName(localeNameWithDash)
     const countryName = LocaleCode.getCountryName(localeNameWithDash)
     const npmPath = `<code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/${localeName}</code>`
     const cdnPath = `[\`${localeName}.min.js\`](https://transloadit.edgly.net/releases/uppy/locales/v${localePackageVersion}/${localeName}.min.js)`
     const githubSource = `[\`${localeName}.js\`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/${localeName}.js)`
-    const mdTableRow = `| ${languageName}<br/> <small>(${countryName})</small> | ${npmPath} | ${cdnPath} | ✏️ ${githubSource} |`
+    const mdTableRow = `| ${languageName}<br/> <small>${countryName}</small>${variant ? `<br /><small>(${variant})</small>` : ''} | ${npmPath} | ${cdnPath} | ✏️ ${githubSource} |`
     mdRows.push(mdTableRow)
   })
 
-  const resultingMdTable = mdTable.concat(mdRows.sort()).join('\n')
+  const resultingMdTable = mdTable.concat(mdRows.sort()).join('\n').replace('%count%', mdRows.length)
 
   let dstpath = path.join(webRoot, 'src', '_template', 'list_of_locale_packs.md')
   fs.writeFileSync(dstpath, resultingMdTable, 'utf-8')

+ 15 - 12
website/src/_template/list_of_locale_packs.md

@@ -1,16 +1,19 @@
 <!-- WARNING! This file was automatically injected. Please run "inject.js" to re-generate -->
 
 
-| Language        | NPM                | CDN                 | Source on GitHub |
+| 14 Locales | NPM                | CDN                 | Source on GitHub |
 | --------------- | ------------------ | ------------------- | ---------------- |
-| Chinese<br/> <small>(China)</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/zh_CN</code> | [`zh_CN.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/zh_CN.min.js) | ✏️ [`zh_CN.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/zh_CN.js) |
-| Chinese<br/> <small>(Taiwan, Province of China)</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/zh_TW</code> | [`zh_TW.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/zh_TW.min.js) | ✏️ [`zh_TW.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/zh_TW.js) |
-| Dutch<br/> <small>(Netherlands)</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/nl_NL</code> | [`nl_NL.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/nl_NL.min.js) | ✏️ [`nl_NL.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/nl_NL.js) |
-| English<br/> <small>(United States)</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/en_US</code> | [`en_US.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/en_US.min.js) | ✏️ [`en_US.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/en_US.js) |
-| French<br/> <small>(France)</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/fr_FR</code> | [`fr_FR.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/fr_FR.min.js) | ✏️ [`fr_FR.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/fr_FR.js) |
-| German<br/> <small>(Germany)</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/de_DE</code> | [`de_DE.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/de_DE.min.js) | ✏️ [`de_DE.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/de_DE.js) |
-| Hungarian<br/> <small>(Hungary)</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/hu_HU</code> | [`hu_HU.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/hu_HU.min.js) | ✏️ [`hu_HU.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/hu_HU.js) |
-| Italian<br/> <small>(Italy)</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/it_IT</code> | [`it_IT.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/it_IT.min.js) | ✏️ [`it_IT.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/it_IT.js) |
-| Persian<br/> <small>(Iran, Islamic Republic of)</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/fa_IR</code> | [`fa_IR.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/fa_IR.min.js) | ✏️ [`fa_IR.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/fa_IR.js) |
-| Russian<br/> <small>(Russian Federation)</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/ru_RU</code> | [`ru_RU.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/ru_RU.min.js) | ✏️ [`ru_RU.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/ru_RU.js) |
-| Spanish<br/> <small>(Spain)</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/es_ES</code> | [`es_ES.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/es_ES.min.js) | ✏️ [`es_ES.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/es_ES.js) |
+| Chinese<br/> <small>China</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/zh_CN</code> | [`zh_CN.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/zh_CN.min.js) | ✏️ [`zh_CN.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/zh_CN.js) |
+| Chinese<br/> <small>Taiwan, Province of China</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/zh_TW</code> | [`zh_TW.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/zh_TW.min.js) | ✏️ [`zh_TW.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/zh_TW.js) |
+| Dutch<br/> <small>Netherlands</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/nl_NL</code> | [`nl_NL.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/nl_NL.min.js) | ✏️ [`nl_NL.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/nl_NL.js) |
+| English<br/> <small>United States</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/en_US</code> | [`en_US.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/en_US.min.js) | ✏️ [`en_US.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/en_US.js) |
+| French<br/> <small>France</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/fr_FR</code> | [`fr_FR.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/fr_FR.min.js) | ✏️ [`fr_FR.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/fr_FR.js) |
+| German<br/> <small>Germany</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/de_DE</code> | [`de_DE.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/de_DE.min.js) | ✏️ [`de_DE.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/de_DE.js) |
+| Hungarian<br/> <small>Hungary</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/hu_HU</code> | [`hu_HU.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/hu_HU.min.js) | ✏️ [`hu_HU.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/hu_HU.js) |
+| Italian<br/> <small>Italy</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/it_IT</code> | [`it_IT.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/it_IT.min.js) | ✏️ [`it_IT.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/it_IT.js) |
+| Persian<br/> <small>Iran, Islamic Republic of</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/fa_IR</code> | [`fa_IR.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/fa_IR.min.js) | ✏️ [`fa_IR.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/fa_IR.js) |
+| Portuguese<br/> <small>Brazil</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/pt_BR</code> | [`pt_BR.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/pt_BR.min.js) | ✏️ [`pt_BR.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/pt_BR.js) |
+| Russian<br/> <small>Russian Federation</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/ru_RU</code> | [`ru_RU.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/ru_RU.min.js) | ✏️ [`ru_RU.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/ru_RU.js) |
+| Serbian<br/> <small>Serbia</small><br /><small>(Latin)</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/sr_RS_Latin</code> | [`sr_RS_Latin.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/sr_RS_Latin.min.js) | ✏️ [`sr_RS_Latin.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/sr_RS_Latin.js) |
+| Spanish<br/> <small>Greenland</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/es_GL</code> | [`es_GL.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/es_GL.min.js) | ✏️ [`es_GL.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/es_GL.js) |
+| Spanish<br/> <small>Spain</small> | <code><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/es_ES</code> | [`es_ES.min.js`](https://transloadit.edgly.net/releases/uppy/locales/v1.2.0/es_ES.min.js) | ✏️ [`es_ES.js`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/es_ES.js) |

+ 1 - 1
website/src/docs/aws-s3-multipart.md

@@ -91,7 +91,7 @@ Return a Promise for an object with keys:
      UploadId: partData.uploadId,
      PartNumber: partData.number,
      Body: '', // Empty, because it is uploaded later
-     Expires: Date.now() + 5 * 60 * 1000
+     Expires: 5 * 60,
    }, (err, url) => { /* there's the url! */ })
    ```
 

+ 2 - 15
website/src/docs/informer.md

@@ -9,6 +9,8 @@ category: 'UI Elements'
 
 The `@uppy/informer` plugin is a pop-up bar for showing notifications. When plugins have some exciting news (or error) to share, they can show a notification here.
 
+Informer gets its data from `uppy.state.info`, which is updated by various plugins via [`uppy.info`](https://uppy.io/docs/uppy/#uppy-info) method.
+
 ```js
 const Informer = require('@uppy/informer')
 
@@ -64,21 +66,6 @@ A unique identifier for this plugin. It defaults to `'Informer'`. Use this if yo
 
 DOM element, CSS selector, or plugin to mount the Informer into.
 
-### `typeColors: {}`
-
-Customize the background and foreground colors for different types of notifications. Supported types are `info`, `warning`, `error`, and `success`. To customize colors, pass an object containing `{ bg, text }` color pairs for each type of notification:
-
-```js
-uppy.use(Informer, {
-  typeColors: {
-    info:    { text: '#fff', bg: '#000000' },
-    warning: { text: '#fff', bg: '#f6a623' },
-    error:   { text: '#fff', bg: '#e74c3c' },
-    success: { text: '#fff', bg: '#7ac824' }
-  }
-})
-```
-
 ### `replaceTargetContent: false`
 
 Remove all children of the `target` element before mounting the Informer. By default, Uppy will append any UI to the `target` DOM element. This is the least dangerous option. However, you may have some fallback HTML inside the `target` element in case JavaScript or Uppy is not available. In that case, you can set `replaceTargetContent: true` to clear the `target` before appending.

+ 1 - 1
website/src/docs/locales.md

@@ -80,6 +80,6 @@ If you speak a language we don’t yet support, you can contribute! Here’s how
 
 1. Go to the [uppy/locales](https://github.com/transloadit/uppy/tree/master/packages/%40uppy/locales/src) directory in the Uppy GitHub repo.
 2. Go to `en_US.js` and copy its contents, as English is the most up-to-date locale.
-3. Press “Create new file”, name it according to the [`language_COUNTRY` format](http://www.i18nguy.com/unicode/language-identifiers.html), make sure to use underscore `_` as a divider. Examples: `en_US`, `en_GB`, `ru_RU`, `ar_AE`.
+3. Press “Create new file”, name it according to the [`language_COUNTRY` format](http://www.i18nguy.com/unicode/language-identifiers.html), make sure to use underscore `_` as a divider. Examples: `en_US`, `en_GB`, `ru_RU`, `ar_AE`. Variants should be trailing, e.g.: `sr_RS_Latin` for Serbian Latin vs Cyrillic.
 4. Paste what you’ve copied from `en_US.js` and use it as a starting point to translate strings into your language.
 5. When you are ready, save the file — this should create a PR that we’ll then review 🎉 Thanks!

+ 1 - 1
website/src/docs/stores.md

@@ -142,4 +142,4 @@ function defaultStore () {
 
 A pattern like this, where users can pass options via a function call if necessary, is recommended.
 
-See the [./src/store](https://github.com/transloadit/uppy/tree/master/src/store) folder in the repository for more inspiration.
+See the [@uppy/store-default](https://github.com/transloadit/uppy/tree/master/packages/%40uppy/store-default) package for more inspiration.

+ 4 - 2
website/src/docs/xhrupload.md

@@ -67,8 +67,10 @@ When `formData` is set to true, this is used as the form field name for the file
 ### `metaFields: null`
 
 Pass an array of field names to limit the metadata fields that will be sent to the endpoint as form fields.
-For example, `metaFields: ['name']` will only send the `name` field.
-Setting this to `null` (the default) will send *all* metadata fields.
+
+* Set this to `['name']` to only send the `name` field.
+* Set this to `null` (the default) to send *all* metadata fields.
+* Set this to an empty array `[]` to not send any fields.
 
 If the `formData` option is set to false, `metaFields` has no effect.
 

+ 3 - 2
website/themes/uppy/layout/index.ejs

@@ -167,11 +167,12 @@
     })
     .use(Uppy.GoogleDrive, { target: Uppy.Dashboard, companionUrl: COMPANION_ENDPOINT })
     .use(Uppy.Instagram, { target: Uppy.Dashboard, companionUrl: COMPANION_ENDPOINT })
+    .use(Uppy.Dropbox, { target: Uppy.Dashboard, companionUrl: COMPANION_ENDPOINT })
     .use(Uppy.Webcam, { target: Uppy.Dashboard })
     .use(Uppy.Url, { target: Uppy.Dashboard, companionUrl: COMPANION_ENDPOINT })
     .use(Uppy.Tus, { endpoint: TUS_ENDPOINT})
 
-  uppy.on('success', (files) => {
-    console.log(`Upload complete! We’ve uploaded these files: ${files}`)
+  uppy.on('success', function (files) {
+    console.log('Upload complete! We’ve uploaded these files:', files)
   })
 </script>

+ 1 - 1
website/themes/uppy/layout/partials/generated_stargazers.ejs

@@ -1 +1 @@
-19226
+19592

+ 1 - 1
website/themes/uppy/layout/stats.ejs

@@ -7,7 +7,7 @@
     To keep Uppy lightweight, we’re aiming to carefully select what packages we include.
     The graph below will help us discover low hanging fruit. Sizes and dependencies shown here
     are for the bundled version of Uppy, which includes all plugins we offer. In production,
-    when you <a href="https://github.com/transloadit/uppy#usage">pick and choose just the ones you need</a>, the size will be much smaller:
+    when you <a href="https://uppy.io/docs/#With-a-module-bundler">pick and choose just the ones you need</a>, the size will be much smaller:
 
     <ul>
       <li>Drag & Drop + Multipart uploads ≈ <code>18 Kb mingz</code></li>

+ 4 - 1
website/themes/uppy/source/css/_page.scss

@@ -351,10 +351,13 @@
   }
 }
 
+.page-docs-locales table {
+  overflow: visible;
+}
 .page-docs-locales table td {
   white-space: nowrap;
+  font-size: 90%;
 }
-
 .page-docs-locales table code {
   font-size: 75%;
 }

部分文件因文件數量過多而無法顯示