Przeglądaj źródła

Merge branch 'master' of github.com:transloadit/uppy

Ifedapo Olarewaju 6 lat temu
rodzic
commit
385fca82c9

+ 17 - 1
CHANGELOG.md

@@ -83,10 +83,10 @@ What we need to do to release Uppy 1.0
 - [ ] QA: add one integration test that uses a Webpack and React/Redux environment (e.g. via `create-react-app`) (@goto-bus-stop)
 - [ ] QA: add one integration test that uses a Provider (investigate if possible with a dedicated Google Drive API key for uppy server, so _with_ oauth dance) (@ife)
 - [ ] QA: add one integration test that uses more exotic (tus) options such as `useFastRemoteRetry` (@arturi)
-- [ ] QA: make it so that all integration tests use `npm pack` and `npm install` first (@ife)
 - [ ] feature: preset for Transloadit that mimics jQuery SDK, check https://github.com/transloadit/jquery-sdk docs (@goto-bus-stop)
 - [ ] feature: basic React Native support (@arturi owner+ios, @ife android)
 - [ ] 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] QA: make it so that all integration tests use `npm pack` and `npm install` first (@ife)
 - [x] docs: on using plugins, all options, list of plugins, i18n
 - [x] feature: beta file recovering after closed tab / browser crash
 - [x] feature: easy integration with React (UppyReact components)
@@ -125,6 +125,22 @@ To Be Released: 2018-06-28.
 - [x] thumbnailgenerator: Polyfill Math.log2 since IE11 doesn't support this method (#892 / @DJWassink)
 - [x] xhrupload: Add `withCredentials` option (#874 / @tuoxiansp)
 
+## 0.25.3
+
+Released: 2018-06-12.
+
+- core: fix/refactor `uppy.close()` and `uppy.removePlugin(plugin)`: Remove plugins immutably when uppy.close() is called, not just uninstall; emit event `plugin-remove` before removing plugin; remove plugins from Dashboard when they are removed from Uppy; check if plugin exists in Uppy before re-rendering, since debounced re-render can happen after a plugin is removed, that’s been causing issues in #890 (#898 / @arturi)
+- tests: run integration tests with npm-installed uppy (#880 / @ifedapoolarewaju)
+- xhrupload: add withCredentials option (#874 / @tuoxiansp, @b1ncer)
+- xhrupload: Move .withCredentials assignment to after open(): IE 10 doesn't allow setting it before open() is called (#2698b599d716743bbf7ed3ac70c648fef0fd8976 / @goto-bus-stop)
+- thumbnailgenerator: Updated ThumbnailGenerator to work with IE (#4ddc9da47b13c9dfe49155d8c3bcd76b9fa494f2 / @DJWassink)
+- core: add eslint-plugin-compat (@goto-bus-stop, #894)
+- dashboard: remove Dashboard bottom margin, since “powered by” has been moved (#a561e4e7a2c18f5092ba03185e0836ffa6796d04 / @arturi)
+- dashboard: fix Dashboard open/close animation on small screen (#982d27f62693c0eb026e381d10157afffe1eeb64 / @arturi)
+- awss3: Don't set uploadURL when success_action_status was missing (#900 / @goto-bus-stop)
+- thumbnailgenerator: Add id option to ThumbnailGenerator (#8cded8160b19d3324d9e14be122c4038ed0b9403 / @arturi)
+- react: tiny improvement for Uppy React example (645e15166a6bd100351de131982df080bc71aac6 / @arturi)
+
 ## 0.25.2
 
 Released: 2018-06-05.

+ 5 - 3
README.md

@@ -15,6 +15,8 @@ Uppy is a sleek, modular JavaScript file uploader that integrates seamlessly wit
 
 Uppy is being developed by the folks at [Transloadit](https://transloadit.com), a versatile file encoding service.
 
+⚠️**ATTENTION** ☢️Uppy [is transitioning](https://github.com/transloadit/uppy/issues/862) into a [Lerna repo](https://lernajs.io/) this/next week, please wait with new PRs to avoid conflicts 💛
+
 ## Example
 
 <img width="700" alt="Uppy UI Demo: modal dialog with a few selected files and an upload button" src="https://github.com/transloadit/uppy/raw/master/uppy-screenshot.jpg">
@@ -63,7 +65,7 @@ $ npm install uppy --save
 
 We recommend installing from npm and then using a module bundler such as [Webpack](http://webpack.github.io/), [Browserify](http://browserify.org/) or [Rollup.js](http://rollupjs.org/).
 
-Add CSS [uppy.min.css](https://transloadit.edgly.net/releases/uppy/v0.25.2/dist/uppy.min.css), either to `<head>` of your HTML page or include in JS, if your bundler of choice supports it — transforms and plugins are available for Browserify and Webpack.
+Add CSS [uppy.min.css](https://transloadit.edgly.net/releases/uppy/v0.25.3/dist/uppy.min.css), either to `<head>` of your HTML page or include in JS, if your bundler of choice supports it — transforms and plugins are available for Browserify and Webpack.
 
 Alternatively, you can also use a pre-built bundle from Transloadit's CDN: Edgly. In that case `Uppy` will attach itself to the global `window.Uppy` object.
 
@@ -72,12 +74,12 @@ Alternatively, you can also use a pre-built bundle from Transloadit's CDN: Edgly
 1\. Add a script to the bottom of `<body>`:
 
 ``` html
-<script src="https://transloadit.edgly.net/releases/uppy/v0.25.2/dist/uppy.min.js"></script>
+<script src="https://transloadit.edgly.net/releases/uppy/v0.25.3/dist/uppy.min.js"></script>
 ```
 
 2\. Add CSS to `<head>`:
 ``` html
-<link href="https://transloadit.edgly.net/releases/uppy/v0.25.2/dist/uppy.min.css" rel="stylesheet">
+<link href="https://transloadit.edgly.net/releases/uppy/v0.25.3/dist/uppy.min.css" rel="stylesheet">
 ```
 
 3\. Initialize:

+ 1 - 1
bin/upload-to-cdn.sh

@@ -8,7 +8,7 @@
 #  - Checks if a tag is being built (on Travis - otherwise opts to continue execution regardless)
 #  - Installs AWS CLI if needed
 #  - Assumed a fully built uppy is in root dir (unless a specific tag was specified, then it's fetched from npm)
-#  - Runs npm pack, and stores files to e.g. https://transloadit.edgly.net/releases/uppy/v0.25.2/dist/uppy.css
+#  - Runs npm pack, and stores files to e.g. https://transloadit.edgly.net/releases/uppy/v0.25.3/dist/uppy.css
 #  - Uses local package by default, if [version] argument was specified, takes package from npm
 #
 # Run as:

+ 2 - 2
examples/cdn-example/index.html

@@ -4,11 +4,11 @@
     <title></title>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1">
-    <link href="https://transloadit.edgly.net/releases/uppy/v0.25.2/dist/uppy.min.css" rel="stylesheet">
+    <link href="https://transloadit.edgly.net/releases/uppy/v0.25.3/dist/uppy.min.css" rel="stylesheet">
   </head>
   <body>
     <button id="uppyModalOpener">Open Modal</button>
-    <script src="https://transloadit.edgly.net/releases/uppy/v0.25.2/dist/uppy.min.js"></script>
+    <script src="https://transloadit.edgly.net/releases/uppy/v0.25.3/dist/uppy.min.js"></script>
     <script>
       const uppy = Uppy.Core({debug: true, autoProceed: false})
         .use(Uppy.Dashboard, { trigger: '#uppyModalOpener' })

+ 3 - 2
examples/react-example/App.js

@@ -18,11 +18,11 @@ module.exports = class App extends React.Component {
   }
 
   componentWillMount () {
-    this.uppy = new Uppy({ autoProceed: false })
+    this.uppy = new Uppy({ id: 'uppy1', autoProceed: true, debug: true })
       .use(Tus, { endpoint: 'https://master.tus.io/files/' })
       .use(GoogleDrive, { host: 'https://server.uppy.io' })
 
-    this.uppy2 = new Uppy({ autoProceed: false })
+    this.uppy2 = new Uppy({ id: 'uppy2', autoProceed: false, debug: true })
       .use(Tus, { endpoint: 'https://master.tus.io/files/' })
   }
 
@@ -93,6 +93,7 @@ module.exports = class App extends React.Component {
         <h2>Progress Bar</h2>
         <ProgressBar
           uppy={this.uppy}
+          hideAfterFinish={false}
         />
       </div>
     )

+ 2 - 2
examples/uppy-with-server/client/index.html

@@ -4,11 +4,11 @@
     <title></title>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1">
-    <link href="https://transloadit.edgly.net/releases/uppy/v0.25.2/dist/uppy.min.css" rel="stylesheet">
+    <link href="https://transloadit.edgly.net/releases/uppy/v0.25.3/dist/uppy.min.css" rel="stylesheet">
   </head>
   <body>
     <button id="uppyModalOpener">Open Modal</button>
-    <script src="https://transloadit.edgly.net/releases/uppy/v0.25.2/dist/uppy.min.js"></script>
+    <script src="https://transloadit.edgly.net/releases/uppy/v0.25.3/dist/uppy.min.js"></script>
     <script>
       const uppy = Uppy.Core({debug: true, autoProceed: false})
         .use(Uppy.Dashboard, { trigger: '#uppyModalOpener' })

+ 59 - 1
package-lock.json

@@ -1,6 +1,6 @@
 {
   "name": "uppy",
-  "version": "0.25.2",
+  "version": "0.25.3",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -12933,6 +12933,58 @@
       "integrity": "sha1-ICtIAhoMTL3i34DeFaF0Q8i0OYA=",
       "dev": true
     },
+    "nock": {
+      "version": "9.3.2",
+      "resolved": "https://registry.npmjs.org/nock/-/nock-9.3.2.tgz",
+      "integrity": "sha512-pulpsRVFneYGpgktmt99s10fFh10zSpYhydwkG28xLps/p19n39lBSq5kjb7UW2YOPyQtt7FLyXuP+xHyRRI0w==",
+      "dev": true,
+      "requires": {
+        "chai": "^4.1.2",
+        "debug": "^3.1.0",
+        "deep-equal": "^1.0.0",
+        "json-stringify-safe": "^5.0.1",
+        "lodash": "^4.17.5",
+        "mkdirp": "^0.5.0",
+        "propagate": "^1.0.0",
+        "qs": "^6.5.1",
+        "semver": "^5.5.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+          "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "lodash": {
+          "version": "4.17.10",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+          "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
+          "dev": true
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        },
+        "qs": {
+          "version": "6.5.2",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+          "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
+          "dev": true
+        },
+        "semver": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
+          "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
+          "dev": true
+        }
+      }
+    },
     "node-fetch": {
       "version": "1.7.1",
       "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.1.tgz",
@@ -14736,6 +14788,12 @@
         "object-assign": "^4.1.1"
       }
     },
+    "propagate": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/propagate/-/propagate-1.0.0.tgz",
+      "integrity": "sha1-AMLa7t2iDofjeCs0Stuhzd1q1wk=",
+      "dev": true
+    },
     "property-is-enumerable-x": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/property-is-enumerable-x/-/property-is-enumerable-x-1.1.0.tgz",

+ 2 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "uppy",
-  "version": "0.25.2",
+  "version": "0.25.3",
   "description": "Extensible JavaScript file upload widget with support for drag&drop, resumable uploads, previews, restrictions, file processing/encoding, remote providers like Instagram, Dropbox, Google Drive, S3 and more :dog:",
   "main": "lib/index.js",
   "jsnext:main": "src/index.js",
@@ -87,6 +87,7 @@
     "mkdirp": "0.5.1",
     "multi-glob": "1.0.1",
     "next-update": "^3.6.0",
+    "nock": "^9.3.2",
     "node-sass": "^4.9.0",
     "npm-run-all": "^4.1.2",
     "onchange": "^3.3.0",

+ 11 - 2
src/core/Core.js

@@ -886,28 +886,37 @@ class Uppy {
    * @param {object} instance The plugin instance to remove.
    */
   removePlugin (instance) {
-    const list = this.plugins[instance.type]
+    this.log(`Removing plugin ${instance.id}`)
+    this.emit('plugin-remove', instance)
 
     if (instance.uninstall) {
       instance.uninstall()
     }
 
+    const list = this.plugins[instance.type].slice()
     const index = list.indexOf(instance)
     if (index !== -1) {
       list.splice(index, 1)
+      this.plugins[instance.type] = list
     }
+
+    const updatedState = this.getState()
+    delete updatedState.plugins[instance.id]
+    this.setState(updatedState)
   }
 
   /**
    * Uninstall all plugins and close down this Uppy instance.
    */
   close () {
+    this.log(`Closing Uppy instance ${this.opts.id}: removing all files and uninstalling plugins`)
+
     this.reset()
 
     this._storeUnsubscribe()
 
     this.iteratePlugins((plugin) => {
-      plugin.uninstall()
+      this.removePlugin(plugin)
     })
   }
 

+ 4 - 5
src/core/Core.test.js

@@ -256,10 +256,10 @@ describe('src/Core', () => {
     const core = new Core()
     core.use(AcquirerPlugin1)
 
-    // const corePauseEventMock = jest.fn()
     const coreCancelEventMock = jest.fn()
     const coreStateUpdateEventMock = jest.fn()
-    // core.on('pause-all', corePauseEventMock)
+    const plugin = core.plugins.acquirer[0]
+
     core.on('cancel-all', coreCancelEventMock)
     core.on('state-update', coreStateUpdateEventMock)
 
@@ -278,9 +278,8 @@ describe('src/Core', () => {
       plugins: {},
       totalProgress: 0
     })
-    expect(core.plugins.acquirer[0].mocks.uninstall.mock.calls.length).toEqual(
-      1
-    )
+    expect(plugin.mocks.uninstall.mock.calls.length).toEqual(1)
+    expect(core.plugins[Object.keys(core.plugins)[0]].length).toEqual(0)
   })
 
   describe('upload hooks', () => {

+ 5 - 1
src/core/Plugin.js

@@ -85,6 +85,10 @@ module.exports = class Plugin {
 
       // API for plugins that require a synchronous rerender.
       this.rerender = (state) => {
+        // plugin could be removed, but this.rerender is debounced below,
+        // so it could still be called even after uppy.removePlugin or uppy.close
+        // hence the check
+        if (!this.uppy.getPlugin(this.id)) return
         this.el = preact.render(this.render(state), targetElement, this.el)
       }
       this._updateUI = debounce(this.rerender)
@@ -137,7 +141,7 @@ module.exports = class Plugin {
   }
 
   unmount () {
-    if (this.el && this.el.parentNode) {
+    if (this.isTargetDOMEl && this.el && this.el.parentNode) {
       this.el.parentNode.removeChild(this.el)
     }
   }

+ 0 - 41
src/core/PromiseWaiter.js

@@ -1,41 +0,0 @@
-/**
- * Wait for multiple Promises to resolve.
- */
-module.exports = class PromiseWaiter {
-  constructor () {
-    this.promises = []
-  }
-
-  add (promise) {
-    this.promises.push(promise)
-
-    const remove = () => {
-      this.remove(promise)
-    }
-    promise.then(remove, remove)
-  }
-
-  remove (promise) {
-    const index = this.promises.indexOf(promise)
-    if (index !== -1) {
-      this.promises.splice(index, 1)
-    }
-  }
-
-  wait () {
-    const promises = this.promises
-    this.promises = []
-
-    function noop () {
-      // No result value
-    }
-
-    // Just wait for a Promise to conclude in some way, whether it's resolution
-    // or rejection. We don't care about the contents.
-    function concluded (promise) {
-      return promise.then(noop, noop)
-    }
-
-    return Promise.all(promises.map(concluded)).then(noop)
-  }
-}

+ 20 - 0
src/plugins/AwsS3/index.js

@@ -148,17 +148,33 @@ module.exports = class AwsS3 extends Plugin {
   }
 
   install () {
+    const { log } = this.uppy
     this.uppy.addPreProcessor(this.prepareUpload)
 
+    let warnedSuccessActionStatus = false
     this.uppy.use(XHRUpload, {
       fieldName: 'file',
       responseUrlFieldName: 'location',
       timeout: this.opts.timeout,
       limit: this.opts.limit,
+      // Get the response data from a successful XMLHttpRequest instance.
+      // `content` is the S3 response as a string.
+      // `xhr` is the XMLHttpRequest instance.
       getResponseData (content, xhr) {
+        const opts = this
+
         // If no response, we've hopefully done a PUT request to the file
         // in the bucket on its full URL.
         if (!isXml(xhr)) {
+          if (opts.method.toUpperCase() === 'POST') {
+            if (!warnedSuccessActionStatus) {
+              log('[AwsS3] No response data found, make sure to set the success_action_status AWS SDK option to 201. See https://uppy.io/docs/aws-s3/#POST-Uploads', 'warning')
+              warnedSuccessActionStatus = true
+            }
+            // The responseURL won't contain the object key. Give up.
+            return { location: null }
+          }
+
           // Trim the query string because it's going to be a bunch of presign
           // parameters for a PUT request—doing a GET request with those will
           // always result in an error
@@ -192,6 +208,10 @@ module.exports = class AwsS3 extends Plugin {
           etag: getValue('ETag')
         }
       },
+
+      // Get the error data from a failed XMLHttpRequest instance.
+      // `content` is the S3 response as a string.
+      // `xhr` is the XMLHttpRequest instance.
       getResponseError (content, xhr) {
         // If no response, we don't have a specific error message, use the default.
         if (!isXml(xhr)) {

+ 15 - 0
src/plugins/Dashboard/index.js

@@ -131,6 +131,7 @@ module.exports = class Dashboard extends Plugin {
     this.isModalOpen = this.isModalOpen.bind(this)
 
     this.addTarget = this.addTarget.bind(this)
+    this.removeTarget = this.removeTarget.bind(this)
     this.hideAllPanels = this.hideAllPanels.bind(this)
     this.showPanel = this.showPanel.bind(this)
     this.getFocusableNodes = this.getFocusableNodes.bind(this)
@@ -149,6 +150,16 @@ module.exports = class Dashboard extends Plugin {
     this.install = this.install.bind(this)
   }
 
+  removeTarget (plugin) {
+    const pluginState = this.getPluginState()
+    // filter out the one we want to remove
+    const newTargets = pluginState.targets.filter(target => target.id !== plugin.id)
+
+    this.setPluginState({
+      targets: newTargets
+    })
+  }
+
   addTarget (plugin) {
     const callerPluginId = plugin.id || plugin.constructor.name
     const callerPluginName = plugin.title || callerPluginId
@@ -362,6 +373,8 @@ module.exports = class Dashboard extends Plugin {
 
     this.updateDashboardElWidth()
     window.addEventListener('resize', this.updateDashboardElWidth)
+
+    this.uppy.on('plugin-remove', this.removeTarget)
   }
 
   removeEvents () {
@@ -372,6 +385,8 @@ module.exports = class Dashboard extends Plugin {
 
     this.removeDragDropListener()
     window.removeEventListener('resize', this.updateDashboardElWidth)
+
+    this.uppy.off('plugin-remove', this.removeTarget)
   }
 
   updateDashboardElWidth () {

+ 1 - 1
src/plugins/ThumbnailGenerator/index.js

@@ -9,7 +9,7 @@ module.exports = class ThumbnailGenerator extends Plugin {
   constructor (uppy, opts) {
     super(uppy, opts)
     this.type = 'thumbnail'
-    this.id = 'ThumbnailGenerator'
+    this.id = this.opts.id || 'ThumbnailGenerator'
     this.title = 'Thumbnail Generator'
     this.queue = []
     this.queueProcessing = false

+ 37 - 0
src/plugins/XHRUpload.test.js

@@ -0,0 +1,37 @@
+const nock = require('nock')
+const Core = require('../core')
+const XHRUpload = require('./XHRUpload')
+
+describe('XHRUpload', () => {
+  describe('getResponseData', () => {
+    it('has the XHRUpload options as its `this`', () => {
+      nock('https://fake-endpoint.uppy.io')
+        .defaultReplyHeaders({
+          'access-control-allow-method': 'POST',
+          'access-control-allow-origin': '*'
+        })
+        .options('/').reply(200, {})
+        .post('/').reply(200, {})
+
+      const core = new Core({ autoProceed: false })
+      const getResponseData = jest.fn(function () {
+        expect(this.some).toEqual('option')
+        return {}
+      })
+      core.use(XHRUpload, {
+        id: 'XHRUpload',
+        endpoint: 'https://fake-endpoint.uppy.io',
+        some: 'option',
+        getResponseData
+      })
+      core.addFile({
+        name: 'test.jpg',
+        data: new Blob([Buffer.alloc(8192)])
+      })
+
+      return core.upload().then(() => {
+        expect(getResponseData).toHaveBeenCalled()
+      })
+    })
+  })
+})

+ 20 - 2
src/scss/_dashboard.scss

@@ -23,13 +23,27 @@
     to { transform: translate3d(-50%, -50%, 0); opacity: 1; }
   }
 
+    @keyframes uppy-Dashboard-slideDownAndFadeIn--small {
+      from { transform: translate3d(0, -20%, 0); opacity: 0; }
+      to { transform: translate3d(0, 0, 0); opacity: 1; }
+    }
+
   @keyframes uppy-Dashboard-slideUpFadeOut {
     from { transform: translate3d(-50%, -50%, 0); opacity: 1; }
     to { transform: translate3d(-50%, -70%, 0); opacity: 0; }
   }
 
+    @keyframes uppy-Dashboard-slideUpFadeOut--small {
+      from { transform: translate3d(0, 0, 0); opacity: 1; }
+      to { transform: translate3d(0, -20%, 0); opacity: 0; }
+    }
+  
   .uppy-Dashboard--modal.uppy-Dashboard--animateOpenClose > .uppy-Dashboard-inner {
-    animation: uppy-Dashboard-slideDownAndFadeIn 0.3s cubic-bezier(0, 0, .2, 1);
+    animation: uppy-Dashboard-slideDownAndFadeIn--small 0.3s cubic-bezier(0, 0, .2, 1);
+
+    @media #{$screen-medium} {
+      animation: uppy-Dashboard-slideDownAndFadeIn 0.3s cubic-bezier(0, 0, .2, 1);
+    }
   }
 
   .uppy-Dashboard--modal.uppy-Dashboard--animateOpenClose > .uppy-Dashboard-overlay {
@@ -37,7 +51,11 @@
   }
 
   .uppy-Dashboard--modal.uppy-Dashboard--animateOpenClose.uppy-Dashboard--isClosing > .uppy-Dashboard-inner {
-    animation: uppy-Dashboard-slideUpFadeOut 0.3s cubic-bezier(0, 0, .2, 1);
+    animation: uppy-Dashboard-slideUpFadeOut--small 0.3s cubic-bezier(0, 0, .2, 1);
+
+    @media #{$screen-medium} {
+      animation: uppy-Dashboard-slideUpFadeOut 0.3s cubic-bezier(0, 0, .2, 1);
+    }
   }
 
   .uppy-Dashboard--modal.uppy-Dashboard--animateOpenClose.uppy-Dashboard--isClosing > .uppy-Dashboard-overlay {

+ 75 - 0
website/src/_posts/2018-06-0.25.md

@@ -0,0 +1,75 @@
+---
+title: "Uppy 0.25: Drag drop links or images from webpages, improved selecting in providers, interactive components in i18n strings"
+date: 2018-06-07
+author: renee
+image: ""
+published: false
+---
+
+Uppy 0.25 brings drag drop links or images from webpages, improved selecting in provider view, interactive components in i18n strings.
+
+<!--more-->
+
+## i18n Strings With Interactive Components
+
+⚠️ **breaking**
+
+We’ve changed how i18n strings work with interactive components. We now use placeholder for those interactive buttons, so it works nicely in languages that have different word order than English. Example:
+
+```js
+dropPasteImport: 'Drop files here, paste, import from one of the locations above or %{browse}'
+browse: 'browse'
+```
+
+`%{browse}` will be replaced with a button/link.
+
+We can’t do this in all situations yet, because some parts of some strings need to be wrapped in Preact elements, which the Translator can’t handle.
+
+Here’s a list of strings that were changed in this release, please update those in your locales:
+
+- core: `failedToUpload` needs to contain `%{file}`, substituted by the name of the file that failed
+- dashboard: `dropPaste` and `dropPasteImport` need to contain `%{browse}`, substituted by the "browse" text button
+- dashboard: `editing` needs to contain `%{file}`, substituted by the name of the file being edited
+- dashboard: `fileSource` and `importFrom` need to contain `%{name}`, substituted by the name of the provider
+- dragdrop: `dropHereOr` needs to contain `%{browse}`, substituted by the "browse" text button
+
+See full list of locale strings for each plugin you are using on [Uppy Docs](/docs/).
+
+## React Documentation
+
+React docs have been improved: we now have a separate page for each Uppy React wrapper component we offer.
+
+- The id option is listed on each plugin's documentation page.
+- The replaceTargetContent option is listed on UI plugin documentation pages.
+- The locale option is described on each plugin documentation page, and includes a short description for each string. The default value is removed from the snippet at the top of the ## Options section to save some space (since it's a very large object sometimes).
+
+## Drag & Drop Links or Images From Webpages
+
+<figure class="wide"><video alt="Demo video showing Uppy with Url plugin that accepts drag and dropped urls" controls autoplay><source src="/images/blog/0.25/link-drop-demo.mp4" type="video/mp4">Your browser does not support the video tag, you can <a href="/images/blog/0.25/link-drop-demo.mp4">download the video</a> to watch it.</video></figure>
+
+## Select In Provider View Vefore Adding Files
+
+Selecting files doesn’t add files to Uppy immediately anymore. Instead a “Select” button appears (with a counter), and pressing that adds all the files with checked checkboxes and closes the Instagram or Google Drive overlay. Cancel discards the selection and also closes the overlay.
+
+This addresses an undesirable case where `autoProceed: true` would begin uploading files the moment you ticked a checkbox, and you couldn’t see what was going on because the provider overlay was still open.
+
+## Typescript Definitions
+
+...
+
+## Other cool things
+
+- Fix: Debounce render calls again, fixes #669 #796 by goto-bus-stop
+- Fix: XHRUPload canceled uploads progress events #864 
+- Improvement: ⚠️ **breaking** Remove `uppy.run()` — everything is now run automatically, you only need to call `.use()` for plugins that you need, as usual (#793 / @goto-bus-stop)
+- Improvement: Dashboard open/close animation
+- Improvement: You can now hide action buttons in Dashboard and StatusBar #821
+- Improvement: Pass `allowedFileTypes` and `maxNumberOfFiles` to `input[type=file]` to add restrictions to the system file picking dialog too
+- Improvement: merge meta data when add file #810
+- Fix: More robust failure handling for Transloadit, closes #708 (#805)
+
+<img class="border" src="/images/blog/0.25/">
+
+Have fun,
+
+The Uppy Team

+ 2 - 2
website/src/docs/index.md

@@ -47,12 +47,12 @@ Alternatively, you can also use a pre-built bundle from Transloadit's CDN: Edgly
 1\. Add a script to the bottom of `<body>`:
 
 ``` html
-<script src="https://transloadit.edgly.net/releases/uppy/v0.25.2/dist/uppy.min.js"></script>
+<script src="https://transloadit.edgly.net/releases/uppy/v0.25.3/dist/uppy.min.js"></script>
 ```
 
 2\. Add CSS to `<head>`:
 ``` html
-<link href="https://transloadit.edgly.net/releases/uppy/v0.25.2/dist/uppy.min.css" rel="stylesheet">
+<link href="https://transloadit.edgly.net/releases/uppy/v0.25.3/dist/uppy.min.css" rel="stylesheet">
 ```
 
 3\. Initialize:

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

@@ -12,7 +12,7 @@ Plugins are what makes Uppy useful: they help select, manipulate and upload file
   - [DragDrop](/docs/dragdrop) — plain and simple drag-and-drop area
   - [FileInput](/docs/fileinput) — even more plain and simple, just a button
   - [Webcam](/docs/webcam) — upload selfies or audio / video recordings
-  - [Provider Plugins](/docs/providers) (remote sources that work through [Uppy Server](/docs/uppy-server/))
+  - [Provider Plugins](/docs/providers) (remote sources that work through [Uppy Server](/docs/server/))
     - [Dropbox](/docs/dropbox) – import files from Dropbox
     - [GoogleDrive](/docs/google-drive) – import files from Google Drive
     - [Instagram](/docs/instagram) – import files from Instagram

+ 2 - 2
website/src/examples/i18n/app.html

@@ -1,11 +1,11 @@
 <!-- Basic Uppy styles. You can use Transloadit's CDN, Edgly:
-https://transloadit.edgly.net/releases/uppy/v0.25.2/dist/uppy.min.css -->
+https://transloadit.edgly.net/releases/uppy/v0.25.3/dist/uppy.min.css -->
 <link rel="stylesheet" href="/uppy/uppy.min.css">
 
 <div class="UppyDragDrop"></div>
 
 <!-- Load Uppy pre-built bundled version. You can use Transloadit's CDN, Edgly:
-https://transloadit.edgly.net/releases/uppy/v0.25.2/dist/uppy.min.js -->
+https://transloadit.edgly.net/releases/uppy/v0.25.3/dist/uppy.min.js -->
 <script src="/uppy/uppy.min.js"></script>
 <script>
   var uppy = Uppy.Core({ debug: true });

+ 1 - 1
website/src/examples/transloadit/app.es6

@@ -55,7 +55,7 @@ function initUppy () {
       inline: true,
       maxHeight: 400,
       target: '#uppy-dashboard-container',
-      note: 'Images and video only, 1–2 files, up to 1 MB'
+      note: 'Images only, 1–2 files, up to 1 MB'
     })
     .use(Instagram, { target: Dashboard, host: 'https://api2.transloadit.com/uppy-server' })
     .use(Webcam, { target: Dashboard })

BIN
website/src/images/blog/0.25/link-drop-demo.mp4


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

@@ -79,8 +79,8 @@
   <p>© <%- date(Date.now(), 'YYYY') %> <a href="https://transloadit.com" rel="noreferrer noopener" target="_blank">Transloadit</a></p>
 </footer>
 
-<link href="https://transloadit.edgly.net/releases/uppy/v0.25.2/dist/uppy.min.css" rel="stylesheet">
-<script src="https://transloadit.edgly.net/releases/uppy/v0.25.2/dist/uppy.min.js"></script>
+<link href="https://transloadit.edgly.net/releases/uppy/v0.25.3/dist/uppy.min.css" rel="stylesheet">
+<script src="https://transloadit.edgly.net/releases/uppy/v0.25.3/dist/uppy.min.js"></script>
 
 <script>
   var PROTOCOL = location.protocol === 'https:' ? 'https' : 'http'