Adding in Drag and Drop support to fix #45 (#56)

* Merging file drop

* Fixing double drop
This commit is contained in:
Paul Kinlan
2018-06-29 16:37:48 +01:00
committed by Jake Archibald
parent 3035a68b90
commit 7c220b1a92
7 changed files with 386 additions and 209 deletions

View File

@@ -21,8 +21,8 @@
"integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
"dev": true,
"requires": {
"delegates": "1.0.0",
"readable-stream": "2.3.5"
"delegates": "^1.0.0",
"readable-stream": "^2.0.6"
}
},
"balanced-match": {
@@ -43,7 +43,7 @@
"integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=",
"dev": true,
"requires": {
"readable-stream": "2.3.5"
"readable-stream": "^2.0.5"
}
},
"block-stream": {
@@ -52,7 +52,7 @@
"integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
"dev": true,
"requires": {
"inherits": "2.0.3"
"inherits": "~2.0.0"
}
},
"brace-expansion": {
@@ -61,7 +61,7 @@
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": {
"balanced-match": "1.0.0",
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
@@ -72,8 +72,8 @@
"dev": true,
"requires": {
"base64-js": "0.0.8",
"ieee754": "1.1.8",
"isarray": "1.0.0"
"ieee754": "^1.1.4",
"isarray": "^1.0.0"
}
},
"buffer-crc32": {
@@ -88,10 +88,10 @@
"integrity": "sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==",
"dev": true,
"requires": {
"get-proxy": "2.1.0",
"isurl": "1.0.0",
"tunnel-agent": "0.6.0",
"url-to-options": "1.0.1"
"get-proxy": "^2.0.0",
"isurl": "^1.0.0-alpha5",
"tunnel-agent": "^0.6.0",
"url-to-options": "^1.0.1"
}
},
"code-point-at": {
@@ -106,7 +106,7 @@
"integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
"dev": true,
"requires": {
"graceful-readlink": "1.0.1"
"graceful-readlink": ">= 1.0.0"
}
},
"concat-map": {
@@ -121,8 +121,8 @@
"integrity": "sha1-q6CXR9++TD5w52am5BWG4YWfxvI=",
"dev": true,
"requires": {
"ini": "1.3.5",
"proto-list": "1.2.4"
"ini": "^1.3.4",
"proto-list": "~1.2.1"
}
},
"console-control-strings": {
@@ -158,14 +158,14 @@
"integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=",
"dev": true,
"requires": {
"decompress-tar": "4.1.1",
"decompress-tarbz2": "4.1.1",
"decompress-targz": "4.1.1",
"decompress-unzip": "4.0.1",
"graceful-fs": "4.1.11",
"make-dir": "1.2.0",
"pify": "2.3.0",
"strip-dirs": "2.1.0"
"decompress-tar": "^4.0.0",
"decompress-tarbz2": "^4.0.0",
"decompress-targz": "^4.0.0",
"decompress-unzip": "^4.0.1",
"graceful-fs": "^4.1.10",
"make-dir": "^1.0.0",
"pify": "^2.3.0",
"strip-dirs": "^2.0.0"
},
"dependencies": {
"pify": {
@@ -182,7 +182,7 @@
"integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=",
"dev": true,
"requires": {
"mimic-response": "1.0.0"
"mimic-response": "^1.0.0"
}
},
"decompress-tar": {
@@ -191,9 +191,9 @@
"integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==",
"dev": true,
"requires": {
"file-type": "5.2.0",
"is-stream": "1.1.0",
"tar-stream": "1.5.5"
"file-type": "^5.2.0",
"is-stream": "^1.1.0",
"tar-stream": "^1.5.2"
}
},
"decompress-tarbz2": {
@@ -202,11 +202,11 @@
"integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==",
"dev": true,
"requires": {
"decompress-tar": "4.1.1",
"file-type": "6.2.0",
"is-stream": "1.1.0",
"seek-bzip": "1.0.5",
"unbzip2-stream": "1.2.5"
"decompress-tar": "^4.1.0",
"file-type": "^6.1.0",
"is-stream": "^1.1.0",
"seek-bzip": "^1.0.5",
"unbzip2-stream": "^1.0.9"
},
"dependencies": {
"file-type": {
@@ -223,9 +223,9 @@
"integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==",
"dev": true,
"requires": {
"decompress-tar": "4.1.1",
"file-type": "5.2.0",
"is-stream": "1.1.0"
"decompress-tar": "^4.1.1",
"file-type": "^5.2.0",
"is-stream": "^1.1.0"
}
},
"decompress-unzip": {
@@ -234,10 +234,10 @@
"integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=",
"dev": true,
"requires": {
"file-type": "3.9.0",
"get-stream": "2.3.1",
"pify": "2.3.0",
"yauzl": "2.9.1"
"file-type": "^3.8.0",
"get-stream": "^2.2.0",
"pify": "^2.3.0",
"yauzl": "^2.4.2"
},
"dependencies": {
"file-type": {
@@ -252,8 +252,8 @@
"integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=",
"dev": true,
"requires": {
"object-assign": "4.1.1",
"pinkie-promise": "2.0.1"
"object-assign": "^4.0.1",
"pinkie-promise": "^2.0.0"
}
},
"pify": {
@@ -282,17 +282,17 @@
"integrity": "sha512-DpO9K1sXAST8Cpzb7kmEhogJxymyVUd5qz/vCOSyvwtp2Klj2XcDt5YUuasgxka44SxF0q5RriKIwJmQHG2AuA==",
"dev": true,
"requires": {
"caw": "2.0.1",
"content-disposition": "0.5.2",
"decompress": "4.2.0",
"ext-name": "5.0.0",
"caw": "^2.0.0",
"content-disposition": "^0.5.2",
"decompress": "^4.0.0",
"ext-name": "^5.0.0",
"file-type": "5.2.0",
"filenamify": "2.0.0",
"get-stream": "3.0.0",
"got": "7.1.0",
"make-dir": "1.2.0",
"p-event": "1.3.0",
"pify": "3.0.0"
"filenamify": "^2.0.0",
"get-stream": "^3.0.0",
"got": "^7.0.0",
"make-dir": "^1.0.0",
"p-event": "^1.0.0",
"pify": "^3.0.0"
}
},
"duplexer3": {
@@ -307,7 +307,7 @@
"integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
"dev": true,
"requires": {
"once": "1.4.0"
"once": "^1.4.0"
}
},
"error-ex": {
@@ -316,7 +316,7 @@
"integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=",
"dev": true,
"requires": {
"is-arrayish": "0.2.1"
"is-arrayish": "^0.2.1"
}
},
"escape-string-regexp": {
@@ -331,7 +331,7 @@
"integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==",
"dev": true,
"requires": {
"mime-db": "1.33.0"
"mime-db": "^1.28.0"
}
},
"ext-name": {
@@ -340,8 +340,8 @@
"integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==",
"dev": true,
"requires": {
"ext-list": "2.2.2",
"sort-keys-length": "1.0.1"
"ext-list": "^2.0.0",
"sort-keys-length": "^1.0.0"
}
},
"extend": {
@@ -356,7 +356,7 @@
"integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
"dev": true,
"requires": {
"pend": "1.2.0"
"pend": "~1.2.0"
}
},
"file-type": {
@@ -377,9 +377,9 @@
"integrity": "sha1-vRYiYsC26Uv7zc8Zo7uzdk94VpU=",
"dev": true,
"requires": {
"filename-reserved-regex": "2.0.0",
"strip-outer": "1.0.0",
"trim-repeated": "1.0.0"
"filename-reserved-regex": "^2.0.0",
"strip-outer": "^1.0.0",
"trim-repeated": "^1.0.0"
}
},
"fs.realpath": {
@@ -394,10 +394,10 @@
"integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=",
"dev": true,
"requires": {
"graceful-fs": "4.1.11",
"inherits": "2.0.3",
"mkdirp": "0.5.1",
"rimraf": "2.6.2"
"graceful-fs": "^4.1.2",
"inherits": "~2.0.0",
"mkdirp": ">=0.5 0",
"rimraf": "2"
}
},
"fstream-ignore": {
@@ -406,9 +406,9 @@
"integrity": "sha1-nDHa40dnAY/h0kmyTa2mfQktoQU=",
"dev": true,
"requires": {
"fstream": "1.0.11",
"inherits": "2.0.3",
"minimatch": "3.0.4"
"fstream": "^1.0.0",
"inherits": "2",
"minimatch": "^3.0.0"
}
},
"gauge": {
@@ -417,14 +417,14 @@
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"dev": true,
"requires": {
"aproba": "1.2.0",
"console-control-strings": "1.1.0",
"has-unicode": "2.0.1",
"object-assign": "4.1.1",
"signal-exit": "3.0.2",
"string-width": "1.0.2",
"strip-ansi": "3.0.1",
"wide-align": "1.1.2"
"aproba": "^1.0.3",
"console-control-strings": "^1.0.0",
"has-unicode": "^2.0.0",
"object-assign": "^4.1.0",
"signal-exit": "^3.0.0",
"string-width": "^1.0.1",
"strip-ansi": "^3.0.1",
"wide-align": "^1.1.0"
}
},
"get-proxy": {
@@ -433,7 +433,7 @@
"integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==",
"dev": true,
"requires": {
"npm-conf": "1.1.3"
"npm-conf": "^1.1.0"
}
},
"get-stream": {
@@ -448,12 +448,12 @@
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"dev": true,
"requires": {
"fs.realpath": "1.0.0",
"inflight": "1.0.6",
"inherits": "2.0.3",
"minimatch": "3.0.4",
"once": "1.4.0",
"path-is-absolute": "1.0.1"
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"got": {
@@ -462,20 +462,20 @@
"integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==",
"dev": true,
"requires": {
"decompress-response": "3.3.0",
"duplexer3": "0.1.4",
"get-stream": "3.0.0",
"is-plain-obj": "1.1.0",
"is-retry-allowed": "1.1.0",
"is-stream": "1.1.0",
"isurl": "1.0.0",
"lowercase-keys": "1.0.0",
"p-cancelable": "0.3.0",
"p-timeout": "1.2.1",
"safe-buffer": "5.1.1",
"timed-out": "4.0.1",
"url-parse-lax": "1.0.0",
"url-to-options": "1.0.1"
"decompress-response": "^3.2.0",
"duplexer3": "^0.1.4",
"get-stream": "^3.0.0",
"is-plain-obj": "^1.1.0",
"is-retry-allowed": "^1.0.0",
"is-stream": "^1.0.0",
"isurl": "^1.0.0-alpha5",
"lowercase-keys": "^1.0.0",
"p-cancelable": "^0.3.0",
"p-timeout": "^1.1.1",
"safe-buffer": "^5.0.1",
"timed-out": "^4.0.0",
"url-parse-lax": "^1.0.0",
"url-to-options": "^1.0.1"
}
},
"graceful-fs": {
@@ -502,7 +502,7 @@
"integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==",
"dev": true,
"requires": {
"has-symbol-support-x": "1.4.2"
"has-symbol-support-x": "^1.4.1"
}
},
"has-unicode": {
@@ -529,8 +529,8 @@
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"requires": {
"once": "1.4.0",
"wrappy": "1.0.2"
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
@@ -557,7 +557,7 @@
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"dev": true,
"requires": {
"number-is-nan": "1.0.1"
"number-is-nan": "^1.0.0"
}
},
"is-natural-number": {
@@ -602,8 +602,8 @@
"integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==",
"dev": true,
"requires": {
"has-to-string-tag-x": "1.4.1",
"is-object": "1.0.1"
"has-to-string-tag-x": "^1.2.0",
"is-object": "^1.0.1"
}
},
"load-json-file": {
@@ -612,10 +612,10 @@
"integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
"dev": true,
"requires": {
"graceful-fs": "4.1.11",
"parse-json": "2.2.0",
"pify": "2.3.0",
"strip-bom": "3.0.0"
"graceful-fs": "^4.1.2",
"parse-json": "^2.2.0",
"pify": "^2.0.0",
"strip-bom": "^3.0.0"
},
"dependencies": {
"pify": {
@@ -638,7 +638,7 @@
"integrity": "sha512-aNUAa4UMg/UougV25bbrU4ZaaKNjJ/3/xnvg/twpmKROPdKZPZ9wGgI0opdZzO8q/zUFawoUuixuOv33eZ61Iw==",
"dev": true,
"requires": {
"pify": "3.0.0"
"pify": "^3.0.0"
}
},
"mime-db": {
@@ -659,7 +659,7 @@
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": {
"brace-expansion": "1.1.11"
"brace-expansion": "^1.1.7"
}
},
"minimist": {
@@ -697,16 +697,16 @@
"integrity": "sha1-7DqP3gcZC2ny/kNMOVo+aUaEG1Y=",
"dev": true,
"requires": {
"download": "6.2.5",
"extend": "3.0.1",
"load-json-file": "2.0.0",
"minimist": "1.2.0",
"mkdirp": "0.5.1",
"npm-cache-filename": "1.0.2",
"npmlog": "4.1.2",
"rimraf": "2.6.2",
"tar-pack": "3.4.1",
"write-json-file": "2.3.0"
"download": "^6.2.2",
"extend": "^3.0.1",
"load-json-file": "^2.0.0",
"minimist": "^1.2.0",
"mkdirp": "^0.5.1",
"npm-cache-filename": "^1.0.2",
"npmlog": "^4.1.0",
"rimraf": "^2.6.1",
"tar-pack": "^3.4.0",
"write-json-file": "^2.2.0"
}
},
"npm-cache-filename": {
@@ -721,8 +721,8 @@
"integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==",
"dev": true,
"requires": {
"config-chain": "1.1.11",
"pify": "3.0.0"
"config-chain": "^1.1.11",
"pify": "^3.0.0"
}
},
"npmlog": {
@@ -731,10 +731,10 @@
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"dev": true,
"requires": {
"are-we-there-yet": "1.1.4",
"console-control-strings": "1.1.0",
"gauge": "2.7.4",
"set-blocking": "2.0.0"
"are-we-there-yet": "~1.1.2",
"console-control-strings": "~1.1.0",
"gauge": "~2.7.3",
"set-blocking": "~2.0.0"
}
},
"number-is-nan": {
@@ -755,7 +755,7 @@
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"requires": {
"wrappy": "1.0.2"
"wrappy": "1"
}
},
"p-cancelable": {
@@ -770,7 +770,7 @@
"integrity": "sha1-jmtPT2XHK8W2/ii3XtqHT5akoIU=",
"dev": true,
"requires": {
"p-timeout": "1.2.1"
"p-timeout": "^1.1.1"
}
},
"p-finally": {
@@ -785,7 +785,7 @@
"integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=",
"dev": true,
"requires": {
"p-finally": "1.0.0"
"p-finally": "^1.0.0"
}
},
"parse-json": {
@@ -794,7 +794,7 @@
"integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
"dev": true,
"requires": {
"error-ex": "1.3.1"
"error-ex": "^1.2.0"
}
},
"path-is-absolute": {
@@ -827,7 +827,7 @@
"integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
"dev": true,
"requires": {
"pinkie": "2.0.4"
"pinkie": "^2.0.0"
}
},
"prepend-http": {
@@ -854,13 +854,13 @@
"integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==",
"dev": true,
"requires": {
"core-util-is": "1.0.2",
"inherits": "2.0.3",
"isarray": "1.0.0",
"process-nextick-args": "2.0.0",
"safe-buffer": "5.1.1",
"string_decoder": "1.0.3",
"util-deprecate": "1.0.2"
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.0.3",
"util-deprecate": "~1.0.1"
}
},
"rimraf": {
@@ -869,7 +869,7 @@
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
"dev": true,
"requires": {
"glob": "7.1.2"
"glob": "^7.0.5"
}
},
"safe-buffer": {
@@ -884,7 +884,7 @@
"integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=",
"dev": true,
"requires": {
"commander": "2.8.1"
"commander": "~2.8.1"
}
},
"set-blocking": {
@@ -905,7 +905,7 @@
"integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
"dev": true,
"requires": {
"is-plain-obj": "1.1.0"
"is-plain-obj": "^1.0.0"
}
},
"sort-keys-length": {
@@ -914,7 +914,7 @@
"integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=",
"dev": true,
"requires": {
"sort-keys": "1.1.2"
"sort-keys": "^1.0.0"
}
},
"string-width": {
@@ -923,9 +923,9 @@
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"dev": true,
"requires": {
"code-point-at": "1.1.0",
"is-fullwidth-code-point": "1.0.0",
"strip-ansi": "3.0.1"
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"strip-ansi": "^3.0.0"
}
},
"string_decoder": {
@@ -934,7 +934,7 @@
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
"dev": true,
"requires": {
"safe-buffer": "5.1.1"
"safe-buffer": "~5.1.0"
}
},
"strip-ansi": {
@@ -943,7 +943,7 @@
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
"ansi-regex": "2.1.1"
"ansi-regex": "^2.0.0"
}
},
"strip-bom": {
@@ -958,7 +958,7 @@
"integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==",
"dev": true,
"requires": {
"is-natural-number": "4.0.1"
"is-natural-number": "^4.0.1"
}
},
"strip-outer": {
@@ -967,7 +967,7 @@
"integrity": "sha1-qsC6YNLpDF1PJ1/Yhp/ZotMQ/7g=",
"dev": true,
"requires": {
"escape-string-regexp": "1.0.5"
"escape-string-regexp": "^1.0.2"
}
},
"tar": {
@@ -976,9 +976,9 @@
"integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=",
"dev": true,
"requires": {
"block-stream": "0.0.9",
"fstream": "1.0.11",
"inherits": "2.0.3"
"block-stream": "*",
"fstream": "^1.0.2",
"inherits": "2"
}
},
"tar-pack": {
@@ -987,14 +987,14 @@
"integrity": "sha512-PPRybI9+jM5tjtCbN2cxmmRU7YmqT3Zv/UDy48tAh2XRkLa9bAORtSWLkVc13+GJF+cdTh1yEnHEk3cpTaL5Kg==",
"dev": true,
"requires": {
"debug": "2.6.9",
"fstream": "1.0.11",
"fstream-ignore": "1.0.5",
"once": "1.4.0",
"readable-stream": "2.3.5",
"rimraf": "2.6.2",
"tar": "2.2.1",
"uid-number": "0.0.6"
"debug": "^2.2.0",
"fstream": "^1.0.10",
"fstream-ignore": "^1.0.5",
"once": "^1.3.3",
"readable-stream": "^2.1.4",
"rimraf": "^2.5.1",
"tar": "^2.2.1",
"uid-number": "^0.0.6"
}
},
"tar-stream": {
@@ -1003,10 +1003,10 @@
"integrity": "sha512-mQdgLPc/Vjfr3VWqWbfxW8yQNiJCbAZ+Gf6GDu1Cy0bdb33ofyiNGBtAY96jHFhDuivCwgW1H9DgTON+INiXgg==",
"dev": true,
"requires": {
"bl": "1.2.1",
"end-of-stream": "1.4.1",
"readable-stream": "2.3.5",
"xtend": "4.0.1"
"bl": "^1.0.0",
"end-of-stream": "^1.0.0",
"readable-stream": "^2.0.0",
"xtend": "^4.0.0"
}
},
"through": {
@@ -1027,7 +1027,7 @@
"integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=",
"dev": true,
"requires": {
"escape-string-regexp": "1.0.5"
"escape-string-regexp": "^1.0.2"
}
},
"tunnel-agent": {
@@ -1036,7 +1036,7 @@
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
"dev": true,
"requires": {
"safe-buffer": "5.1.1"
"safe-buffer": "^5.0.1"
}
},
"uid-number": {
@@ -1051,8 +1051,8 @@
"integrity": "sha512-izD3jxT8xkzwtXRUZjtmRwKnZoeECrfZ8ra/ketwOcusbZEp4mjULMnJOCfTDZBgGQAAY1AJ/IgxcwkavcX9Og==",
"dev": true,
"requires": {
"buffer": "3.6.0",
"through": "2.3.8"
"buffer": "^3.0.1",
"through": "^2.3.6"
}
},
"url-parse-lax": {
@@ -1061,7 +1061,7 @@
"integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=",
"dev": true,
"requires": {
"prepend-http": "1.0.4"
"prepend-http": "^1.0.1"
}
},
"url-to-options": {
@@ -1082,7 +1082,7 @@
"integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
"dev": true,
"requires": {
"string-width": "1.0.2"
"string-width": "^1.0.2"
}
},
"wrappy": {
@@ -1097,9 +1097,9 @@
"integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==",
"dev": true,
"requires": {
"graceful-fs": "4.1.11",
"imurmurhash": "0.1.4",
"signal-exit": "3.0.2"
"graceful-fs": "^4.1.11",
"imurmurhash": "^0.1.4",
"signal-exit": "^3.0.2"
}
},
"write-json-file": {
@@ -1108,12 +1108,12 @@
"integrity": "sha1-K2TIozAE1UuGmMdtWFp3zrYdoy8=",
"dev": true,
"requires": {
"detect-indent": "5.0.0",
"graceful-fs": "4.1.11",
"make-dir": "1.2.0",
"pify": "3.0.0",
"sort-keys": "2.0.0",
"write-file-atomic": "2.3.0"
"detect-indent": "^5.0.0",
"graceful-fs": "^4.1.2",
"make-dir": "^1.0.0",
"pify": "^3.0.0",
"sort-keys": "^2.0.0",
"write-file-atomic": "^2.0.0"
},
"dependencies": {
"sort-keys": {
@@ -1122,7 +1122,7 @@
"integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=",
"dev": true,
"requires": {
"is-plain-obj": "1.1.0"
"is-plain-obj": "^1.0.0"
}
}
}
@@ -1139,8 +1139,8 @@
"integrity": "sha1-qBmB6nCleUYTOIPwKcWCGok1mn8=",
"dev": true,
"requires": {
"buffer-crc32": "0.2.13",
"fd-slicer": "1.0.1"
"buffer-crc32": "~0.2.3",
"fd-slicer": "~1.0.1"
}
}
}

View File

@@ -0,0 +1,116 @@
import { bind } from '../../../../lib/util';
import './styles.css';
function firstMatchingItem(list: DataTransferItemList, acceptVal: string): DataTransferItem | undefined {
// Split accepts values by ',' then by '/'. Trim everything & lowercase.
const accepts = acceptVal.toLowerCase().split(',').map(accept => {
return accept.trim().split('/').map(part => part.trim());
}).filter(acceptParts => acceptParts.length === 2); // Filter invalid values
return Array.from(list).find(item => {
if (item.kind !== 'file') return false;
// 'Parse' the type.
const [typeMain, typeSub] = item.type.toLowerCase().split('/').map(s => s.trim());
for (const [acceptMain, acceptSub] of accepts) {
// Look for an exact match, or a partial match if * is accepted, eg image/*.
if (typeMain === acceptMain && (acceptSub === '*' || typeSub === acceptSub)) {
return true;
}
}
return false;
});
}
interface FileDropEventInit extends EventInit {
file: File;
}
export class FileDropEvent extends Event {
private _file: File;
constructor(typeArg: string, eventInitDict: FileDropEventInit) {
super(typeArg, eventInitDict);
this._file = eventInitDict.file;
}
get file(): File {
return this._file;
}
}
/*
Example Usage.
<file-drop
accept='image/*'
class='drop-valid|drop-invalid'
>
[everything in here is a drop target.]
</file-drop>
dropElement.addEventListner('dropfile', (event) => console.log(event.detail))
*/
export class FileDrop extends HTMLElement {
private _dragEnterCount = 0;
constructor() {
super();
this.addEventListener('dragover', (event) => event.preventDefault());
this.addEventListener('drop', this._onDrop);
this.addEventListener('dragenter', this._onDragEnter);
this.addEventListener('dragend', () => this._reset());
this.addEventListener('dragleave', this._onDragLeave);
}
get accept() {
return this.getAttribute('accept') || '';
}
set accept(val: string) {
this.setAttribute('accept', val);
}
@bind
private _onDragEnter(event: DragEvent) {
this._dragEnterCount++;
if (this._dragEnterCount > 1) return;
// We don't have data, attempt to get it and if it matches, set the correct state.
const dragDataItem = firstMatchingItem(event.dataTransfer.items, this.accept);
if (dragDataItem) {
this.classList.add('drop-valid');
} else {
this.classList.add('drop-invalid');
}
}
@bind
private _onDragLeave() {
this._dragEnterCount--;
if (this._dragEnterCount === 0) {
this._reset();
}
}
@bind
private _onDrop(event: DragEvent) {
event.preventDefault();
this._reset();
const dragDataItem = firstMatchingItem(event.dataTransfer.items, this.accept);
if (!dragDataItem) return;
const file = dragDataItem.getAsFile();
if (file === null) return;
this.dispatchEvent(new FileDropEvent('filedrop', { file }));
}
private _reset() {
this._dragEnterCount = 0;
this.classList.remove('drop-valid');
this.classList.remove('drop-invalid');
}
}
customElements.define('file-drop', FileDrop);

View File

@@ -0,0 +1,20 @@
import { FileDropEvent, FileDrop } from ".";
declare global {
interface HTMLElementEventMap {
'filedrop': FileDropEvent;
}
namespace JSX {
interface IntrinsicElements {
'file-drop': FileDropAttributes;
}
interface FileDropAttributes extends HTMLAttributes {
accept?: string;
onfiledrop?: ((this: FileDrop, ev: FileDropEvent) => any) | null;
}
}
}

View File

@@ -0,0 +1,3 @@
file-drop {
display: block;
}

View File

@@ -3,6 +3,8 @@ import { bind, bitmapToImageData } from '../../lib/util';
import * as style from './style.scss';
import Output from '../output';
import Options from '../options';
import { FileDropEvent } from './custom-els/FileDrop';
import './custom-els/FileDrop';
import * as mozJPEG from '../../codecs/mozjpeg/encoder';
import * as identity from '../../codecs/identity/encoder';
@@ -104,6 +106,17 @@ export default class App extends Component<Props, State> {
const fileInput = event.target as HTMLInputElement;
const file = fileInput.files && fileInput.files[0];
if (!file) return;
await this.updateFile(file);
}
@bind
async onFileDrop(event: FileDropEvent) {
const { file } = event;
if (!file) return;
await this.updateFile(file);
}
async updateFile(file: File) {
this.setState({ loading: true });
try {
const bmp = await createImageBitmap(file);
@@ -112,7 +125,7 @@ export default class App extends Component<Props, State> {
this.setState({
source: { data, bmp, file },
error: undefined,
loading: false
loading: false,
});
} catch (err) {
this.setState({ error: 'IMAGE_INVALID', loading: false });
@@ -173,29 +186,33 @@ export default class App extends Component<Props, State> {
loading = loading || images.some(image => image.loading);
return (
<div id="app" class={style.app}>
{(leftImageBmp && rightImageBmp) ? (
<Output leftImg={leftImageBmp} rightImg={rightImageBmp} />
) : (
<div class={style.welcome}>
<h1>Select an image</h1>
<input type="file" onChange={this.onFileChange} />
</div>
)}
{images.map((image, index) => (
<span class={index ? style.rightLabel : style.leftLabel}>{encoderMap[image.encoderState.type].label}</span>
))}
{images.map((image, index) => (
<Options
class={index ? style.rightOptions : style.leftOptions}
encoderState={image.encoderState}
onTypeChange={this.onEncoderChange.bind(this, index)}
onOptionsChange={this.onOptionsChange.bind(this, index)}
/>
))}
{loading && <span style={{ position: 'fixed', top: 0, left: 0 }}>Loading...</span>}
{error && <span style={{ position: 'fixed', top: 0, left: 0 }}>Error: {error}</span>}
</div>
<file-drop accept="image/*" onfiledrop={this.onFileDrop}>
<div id="app" class={style.app}>
{(leftImageBmp && rightImageBmp) ? (
<Output leftImg={leftImageBmp} rightImg={rightImageBmp} />
) : (
<div class={style.welcome}>
<h1>Select an image</h1>
<input type="file" onChange={this.onFileChange} />
</div>
)}
{images.map((image, index) => (
<span class={index ? style.rightLabel : style.leftLabel}>
{encoderMap[image.encoderState.type].label}
</span>
))}
{images.map((image, index) => (
<Options
class={index ? style.rightOptions : style.leftOptions}
encoderState={image.encoderState}
onTypeChange={this.onEncoderChange.bind(this, index)}
onOptionsChange={this.onOptionsChange.bind(this, index)}
/>
))}
{loading && <span style={{ position: 'fixed', top: 0, left: 0 }}>Loading...</span>}
{error && <span style={{ position: 'fixed', top: 0, left: 0 }}>Error: {error}</span>}
</div>
</file-drop>
);
}
}

View File

@@ -46,7 +46,7 @@ Note: These styles are temporary. They will be replaced before going live.
font-size: 150%;
text-align: center;
}
input {
display: inline-block;
width: 16em;
@@ -60,3 +60,24 @@ Note: These styles are temporary. They will be replaced before going live.
cursor: pointer;
}
}
:global {
file-drop {
overflow: hidden;
touch-action: none;
height:100%;
width:100%;
&.drop-valid {
transition: opacity 200ms ease-in-out, background-color 200ms;
opacity: 0.5;
background-color:green;
}
&.drop-invalid {
transition: opacity 200ms ease-in-out, background-color 200ms;
opacity: 0.5;
background-color:red;
}
}
}

View File

@@ -30,12 +30,12 @@ export default class Output extends Component<Props, State> {
}
}
componentWillReceiveProps({ leftImg, rightImg }: Props) {
if (leftImg !== this.props.leftImg && this.canvasLeft) {
drawBitmapToCanvas(this.canvasLeft, leftImg);
componentDidUpdate(prevProps: Props) {
if (prevProps.leftImg !== this.props.leftImg && this.canvasLeft) {
drawBitmapToCanvas(this.canvasLeft, this.props.leftImg);
}
if (rightImg !== this.props.rightImg && this.canvasRight) {
drawBitmapToCanvas(this.canvasRight, rightImg);
if (prevProps.rightImg !== this.props.rightImg && this.canvasRight) {
drawBitmapToCanvas(this.canvasRight, this.props.rightImg);
}
}