react-dropzone 11.5.0 → 11.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26,14 +26,14 @@ export const getInvalidTypeRejectionErr = accept => {
26
26
  export const getTooLargeRejectionErr = maxSize => {
27
27
  return {
28
28
  code: FILE_TOO_LARGE,
29
- message: `File is larger than ${maxSize} bytes`
29
+ message: `File is larger than ${maxSize} ${maxSize === 1 ? 'byte' : 'bytes'}`
30
30
  }
31
31
  }
32
32
 
33
33
  export const getTooSmallRejectionErr = minSize => {
34
34
  return {
35
35
  code: FILE_TOO_SMALL,
36
- message: `File is smaller than ${minSize} bytes`
36
+ message: `File is smaller than ${minSize} ${minSize === 1 ? 'byte' : 'bytes'}`
37
37
  }
38
38
  }
39
39
 
@@ -66,8 +66,8 @@ function isDefined(value) {
66
66
  return value !== undefined && value !== null
67
67
  }
68
68
 
69
- export function allFilesAccepted({ files, accept, minSize, maxSize, multiple, maxFiles }) {
70
- if ((!multiple && files.length > 1) || (multiple && maxFiles >= 1 && files.length > maxFiles) ) {
69
+ export function allFilesAccepted({files, accept, minSize, maxSize, multiple, maxFiles}) {
70
+ if ((!multiple && files.length > 1) || (multiple && maxFiles >= 1 && files.length > maxFiles)) {
71
71
  return false;
72
72
  }
73
73
 
@@ -142,3 +142,37 @@ export function composeEventHandlers(...fns) {
142
142
  return isPropagationStopped(event)
143
143
  })
144
144
  }
145
+
146
+ /**
147
+ * canUseFileSystemAccessAPI checks if the [File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API)
148
+ * is supported by the browser.
149
+ * @returns {boolean}
150
+ */
151
+ export function canUseFileSystemAccessAPI() {
152
+ return 'showOpenFilePicker' in window;
153
+ }
154
+
155
+ /**
156
+ * filePickerOptionsTypes returns the {types} option for https://developer.mozilla.org/en-US/docs/Web/API/window/showOpenFilePicker
157
+ * based on the accept attr (see https://github.com/react-dropzone/attr-accept)
158
+ * E.g: converts ['image/*', 'text/*'] to {'image/*': [], 'text/*': []}
159
+ * @param {string|string[]} accept
160
+ */
161
+ export function filePickerOptionsTypes(accept) {
162
+ accept = typeof accept === 'string' ? accept.split(',') : accept
163
+ return [{
164
+ description: 'everything',
165
+ // TODO: Need to handle filtering more elegantly than this!
166
+ accept: Array.isArray(accept)
167
+ // Accept just MIME types as per spec
168
+ // NOTE: accept can be https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#unique_file_type_specifiers
169
+ ? accept.filter(item =>
170
+ item === 'audio/*' ||
171
+ item === 'video/*' ||
172
+ item === 'image/*' ||
173
+ item === 'text/*' ||
174
+ /\w+\/[-+.\w]+/g.test(item)
175
+ ).reduce((a, b) => ({...a, [b]: []}), {})
176
+ : {},
177
+ }];
178
+ }
@@ -2,12 +2,10 @@ beforeEach(() => {
2
2
  jest.resetModules()
3
3
  })
4
4
 
5
-
6
5
  describe('fileMatchSize()', () => {
7
6
  let utils
8
- beforeEach(async done => {
7
+ beforeEach(async () => {
9
8
  utils = await import('./index')
10
- done()
11
9
  })
12
10
 
13
11
  it('should return true if the file object doesn\'t have a {size} property', () => {
@@ -42,9 +40,8 @@ describe('fileMatchSize()', () => {
42
40
 
43
41
  describe('isIeOrEdge', () => {
44
42
  let utils
45
- beforeEach(async done => {
43
+ beforeEach(async () => {
46
44
  utils = await import('./index')
47
- done()
48
45
  })
49
46
 
50
47
  it('should return true for IE10', () => {
@@ -89,9 +86,8 @@ describe('isPropagationStopped()', () => {
89
86
  const trueFn = jest.fn(() => true)
90
87
 
91
88
  let utils
92
- beforeEach(async done => {
89
+ beforeEach(async () => {
93
90
  utils = await import('./index')
94
- done()
95
91
  })
96
92
 
97
93
  it('should return result of isPropagationStopped() if isPropagationStopped exists', () => {
@@ -109,9 +105,8 @@ describe('isPropagationStopped()', () => {
109
105
 
110
106
  describe('isEvtWithFiles()', () => {
111
107
  let utils
112
- beforeEach(async done => {
108
+ beforeEach(async () => {
113
109
  utils = await import('./index')
114
- done()
115
110
  })
116
111
 
117
112
  it('should return true if some dragged types are files', () => {
@@ -145,9 +140,8 @@ describe('isEvtWithFiles()', () => {
145
140
 
146
141
  describe('composeEventHandlers', () => {
147
142
  let utils
148
- beforeEach(async done => {
143
+ beforeEach(async () => {
149
144
  utils = await import('./index')
150
- done()
151
145
  })
152
146
 
153
147
  it('returns a fn', () => {
@@ -193,9 +187,8 @@ describe('composeEventHandlers', () => {
193
187
 
194
188
  describe('fileAccepted', () => {
195
189
  let utils
196
- beforeEach(async done => {
190
+ beforeEach(async () => {
197
191
  utils = await import('./index')
198
- done()
199
192
  })
200
193
 
201
194
  it('accepts bogus firefox file', () => {
@@ -232,9 +225,8 @@ it('rejects file when single accept criteria as array', () => {
232
225
 
233
226
  describe('allFilesAccepted()', () => {
234
227
  let utils
235
- beforeEach(async done => {
228
+ beforeEach(async () => {
236
229
  utils = await import('./index')
237
- done()
238
230
  })
239
231
  it('rejects file when multiple accept criteria', () => {
240
232
  const files = [createFile('hamster.pdf', 100, 'application/pdf'),createFile('fish.pdf', 100, 'application/pdf')];
@@ -242,29 +234,18 @@ describe('allFilesAccepted()', () => {
242
234
  expect(utils.allFilesAccepted({ files, multiple: true})).toEqual(true)
243
235
  expect(utils.allFilesAccepted({ files, multiple: true, maxFiles: 10 })).toEqual(true)
244
236
  expect(utils.allFilesAccepted({ files, multiple: false, maxFiles: 10 })).toEqual(false)
245
- expect(utils.allFilesAccepted({ files, multiple: true, accept:'image/jpeg' })).toEqual(false)
246
- expect(utils.allFilesAccepted({ files: images, multiple: true,accept:'image/*' })).toEqual(true)
237
+ expect(utils.allFilesAccepted({ files, multiple: true, accept:'image/jpeg' })).toEqual(false)
238
+ expect(utils.allFilesAccepted({ files: images, multiple: true,accept:'image/*' })).toEqual(true)
247
239
  expect(utils.allFilesAccepted({ files, multiple: true, minSize: 110 })).toEqual(false)
248
240
  expect(utils.allFilesAccepted({ files, multiple: true, maxSize: 99 })).toEqual(false)
249
241
  expect(utils.allFilesAccepted({ files, multiple: true, maxFiles: 1 })).toEqual(false)
250
242
  })
251
243
  })
252
244
 
253
- function createFile(name, size, type) {
254
- const file = new File([], name, { type })
255
- Object.defineProperty(file, 'size', {
256
- get() {
257
- return size
258
- }
259
- })
260
- return file
261
- }
262
-
263
245
  describe('ErrorCode', () => {
264
246
  let utils
265
- beforeEach(async done => {
247
+ beforeEach(async () => {
266
248
  utils = await import('./index')
267
- done()
268
249
  })
269
250
 
270
251
  it('should exist and have known error code properties', () => {
@@ -275,3 +256,85 @@ describe('ErrorCode', () => {
275
256
  })
276
257
  })
277
258
 
259
+ describe('canUseFileSystemAccessAPI()', () => {
260
+ let utils
261
+ beforeEach(async () => {
262
+ utils = await import('./index')
263
+ })
264
+
265
+ it('should return false if not', () => {
266
+ expect(utils.canUseFileSystemAccessAPI()).toBe(false)
267
+ })
268
+
269
+ it('should return true if yes', () => {
270
+ // TODO: If we use these in other tests, restore once test is done
271
+ window.showOpenFilePicker = jest.fn()
272
+ expect(utils.canUseFileSystemAccessAPI()).toBe(true)
273
+ })
274
+ })
275
+
276
+ describe('filePickerOptionsTypes()', () => {
277
+ let utils
278
+ beforeEach(async () => {
279
+ utils = await import('./index')
280
+ })
281
+
282
+ it('should return proper types when the arg is a MIME type', () => {
283
+ expect(utils.filePickerOptionsTypes('application/zip')).toEqual([{
284
+ description: 'everything',
285
+ accept: {'application/zip': []}
286
+ }])
287
+ })
288
+
289
+ it('should return proper types when the arg is an array of MIME types', () => {
290
+ expect(utils.filePickerOptionsTypes(['application/zip', 'application/json'])).toEqual([{
291
+ description: 'everything',
292
+ accept: {
293
+ 'application/zip': [],
294
+ 'application/json': []
295
+ }
296
+ }])
297
+ })
298
+
299
+ it("should exclude anything that's not a MIME type", () => {
300
+ expect(utils.filePickerOptionsTypes(['audio/*', 'video/*', 'image/*', '.txt', 'text/*'])).toEqual([{
301
+ description: 'everything',
302
+ accept: {
303
+ 'audio/*': [],
304
+ 'video/*': [],
305
+ 'image/*': [],
306
+ 'text/*': [],
307
+ }
308
+ }])
309
+ })
310
+
311
+ it("should work with comma separated string of MIME types", () => {
312
+ expect(utils.filePickerOptionsTypes('audio/*,video/*,image/*,.txt,text/*,application/zip')).toEqual([{
313
+ description: 'everything',
314
+ accept: {
315
+ 'audio/*': [],
316
+ 'video/*': [],
317
+ 'image/*': [],
318
+ 'text/*': [],
319
+ 'application/zip': []
320
+ }
321
+ }])
322
+ })
323
+
324
+ it('should return empty otherwise', () => {
325
+ expect(utils.filePickerOptionsTypes('')).toEqual([{
326
+ description: 'everything',
327
+ accept: {}
328
+ }])
329
+ })
330
+ })
331
+
332
+ function createFile(name, size, type) {
333
+ const file = new File([], name, { type })
334
+ Object.defineProperty(file, 'size', {
335
+ get() {
336
+ return size
337
+ }
338
+ })
339
+ return file
340
+ }
@@ -19,11 +19,9 @@ module.exports = {
19
19
  serverPort: 8080,
20
20
  moduleAliases: {
21
21
  'react-dropzone': path.resolve(__dirname, './src'),
22
- 'doka': path.resolve(__dirname, './vendor/doka/doka.esm.min.js')
23
22
  },
24
23
  require: [
25
24
  path.join(__dirname, 'examples/theme.css'),
26
- path.join(__dirname, 'vendor/doka/doka.min.css'),
27
25
  ],
28
26
  sections: [
29
27
  {
@@ -85,8 +83,8 @@ module.exports = {
85
83
  name: 'Integrations',
86
84
  sections: [
87
85
  {
88
- name: 'Doka',
89
- content: 'examples/doka/README.md'
86
+ name: 'Pintura',
87
+ content: 'examples/pintura/README.md'
90
88
  }
91
89
  ]
92
90
  }
@@ -0,0 +1,28 @@
1
+ {
2
+ "root": true,
3
+ "parser": "@typescript-eslint/parser",
4
+ "env": {
5
+ "es6": true,
6
+ "browser": true
7
+ },
8
+ "plugins": [
9
+ "import",
10
+ "prettier",
11
+ "react",
12
+ "react-hooks",
13
+ "@typescript-eslint"
14
+ ],
15
+ "extends": [
16
+ "eslint:recommended",
17
+ "plugin:@typescript-eslint/recommended",
18
+ "prettier"
19
+ ],
20
+ "settings": {
21
+ "react": {
22
+ "version": "detect"
23
+ }
24
+ },
25
+ "rules": {
26
+ "@typescript-eslint/no-explicit-any": "off"
27
+ }
28
+ }
@@ -1,140 +0,0 @@
1
- If you'd like to integrate the dropzone with the [doka](https://pqina.nl/doka/?ref=react-dropzone) image editor, you just need to pass either of the selected images to the `create()` method exported by doka:
2
-
3
- ```jsx harmony
4
- import React, {useEffect, useState} from 'react';
5
- import {useDropzone} from 'react-dropzone';
6
-
7
- import {create} from 'doka';
8
-
9
- const thumbsContainer = {
10
- display: "flex",
11
- flexDirection: "row",
12
- flexWrap: "wrap",
13
- marginTop: 16,
14
- padding: 20
15
- };
16
-
17
- const thumb = {
18
- position: "relative",
19
- display: "inline-flex",
20
- borderRadius: 2,
21
- border: "1px solid #eaeaea",
22
- marginBottom: 8,
23
- marginRight: 8,
24
- width: 100,
25
- height: 100,
26
- padding: 4,
27
- boxSizing: "border-box"
28
- };
29
-
30
- const thumbInner = {
31
- display: "flex",
32
- minWidth: 0,
33
- overflow: "hidden"
34
- };
35
-
36
- const img = {
37
- display: "block",
38
- width: "auto",
39
- height: "100%"
40
- };
41
-
42
- const thumbButton = {
43
- position: "absolute",
44
- right: 10,
45
- bottom: 10,
46
- background: "rgba(0,0,0,.8)",
47
- color: "#fff",
48
- border: 0,
49
- borderRadius: ".325em",
50
- cursor: "pointer"
51
- };
52
-
53
- const editImage = (image, done) => {
54
- const imageFile = image.doka ? image.doka.file : image;
55
- const imageState = image.doka ? image.doka.data : {};
56
- create({
57
- // recreate previous state
58
- ...imageState,
59
-
60
- // load original image file
61
- src: imageFile,
62
- outputData: true,
63
-
64
- onconfirm: ({ file, data }) => {
65
- Object.assign(file, {
66
- doka: { file: imageFile, data }
67
- });
68
- done(file);
69
- }
70
- });
71
- };
72
-
73
- function Doka(props) {
74
- const [files, setFiles] = useState([]);
75
- const { getRootProps, getInputProps } = useDropzone({
76
- accept: "image/*",
77
- onDrop: (acceptedFiles) => {
78
- setFiles(
79
- acceptedFiles.map((file) =>
80
- Object.assign(file, {
81
- preview: URL.createObjectURL(file)
82
- })
83
- )
84
- );
85
- }
86
- });
87
-
88
- const thumbs = files.map((file, index) => (
89
- <div style={thumb} key={file.name}>
90
- <div style={thumbInner}>
91
- <img src={file.preview} style={img} alt="" />
92
- </div>
93
- <button
94
- style={thumbButton}
95
- onClick={() =>
96
- editImage(file, (output) => {
97
- const updatedFiles = [...files];
98
-
99
- // replace original image with new image
100
- updatedFiles[index] = output;
101
-
102
- // revoke preview URL for old image
103
- if (file.preview) URL.revokeObjectURL(file.preview);
104
-
105
- // set new preview URL
106
- Object.assign(output, {
107
- preview: URL.createObjectURL(output)
108
- });
109
-
110
- // update view
111
- setFiles(updatedFiles);
112
- })
113
- }
114
- >
115
- edit
116
- </button>
117
- </div>
118
- ));
119
-
120
- useEffect(
121
- () => () => {
122
- // Make sure to revoke the data uris to avoid memory leaks
123
- files.forEach((file) => URL.revokeObjectURL(file.preview));
124
- },
125
- [files]
126
- );
127
-
128
- return (
129
- <section className="container">
130
- <div {...getRootProps({ className: "dropzone" })}>
131
- <input {...getInputProps()} />
132
- <p>Drag 'n' drop some files here, or click to select files</p>
133
- </div>
134
- <aside style={thumbsContainer}>{thumbs}</aside>
135
- </section>
136
- );
137
- }
138
-
139
- <Doka />
140
- ```
package/tslint.json DELETED
@@ -1,101 +0,0 @@
1
- {
2
- "jsRules": {
3
- "class-name": true,
4
- "comment-format": [
5
- true,
6
- "check-space"
7
- ],
8
- "indent": [
9
- true,
10
- "spaces"
11
- ],
12
- "no-duplicate-variable": true,
13
- "no-eval": true,
14
- "no-trailing-whitespace": true,
15
- "no-unsafe-finally": true,
16
- "one-line": [
17
- true,
18
- "check-open-brace",
19
- "check-whitespace"
20
- ],
21
- "quotemark": [
22
- true,
23
- "double"
24
- ],
25
- "semicolon": [
26
- true,
27
- "always"
28
- ],
29
- "triple-equals": [
30
- true,
31
- "allow-null-check"
32
- ],
33
- "variable-name": [
34
- true,
35
- "ban-keywords"
36
- ],
37
- "whitespace": [
38
- true,
39
- "check-branch",
40
- "check-decl",
41
- "check-operator",
42
- "check-separator",
43
- "check-type"
44
- ]
45
- },
46
- "rules": {
47
- "class-name": true,
48
- "comment-format": [
49
- true,
50
- "check-space"
51
- ],
52
- "indent": [
53
- true,
54
- "spaces"
55
- ],
56
- "no-eval": true,
57
- "no-internal-module": true,
58
- "no-trailing-whitespace": true,
59
- "no-unsafe-finally": true,
60
- "no-var-keyword": true,
61
- "one-line": [
62
- true,
63
- "check-open-brace",
64
- "check-whitespace"
65
- ],
66
- "quotemark": [
67
- true,
68
- "double"
69
- ],
70
- "semicolon": [
71
- true,
72
- "always"
73
- ],
74
- "triple-equals": [
75
- true,
76
- "allow-null-check"
77
- ],
78
- "typedef-whitespace": [
79
- true,
80
- {
81
- "call-signature": "nospace",
82
- "index-signature": "nospace",
83
- "parameter": "nospace",
84
- "property-declaration": "nospace",
85
- "variable-declaration": "nospace"
86
- }
87
- ],
88
- "variable-name": [
89
- true,
90
- "ban-keywords"
91
- ],
92
- "whitespace": [
93
- true,
94
- "check-branch",
95
- "check-decl",
96
- "check-operator",
97
- "check-separator",
98
- "check-type"
99
- ]
100
- }
101
- }