react-dropzone 11.5.3 → 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.
- package/.eslintignore +1 -3
- package/.eslintrc +1 -1
- package/.husky/commit-msg +5 -0
- package/.husky/pre-commit +5 -0
- package/.nvmrc +1 -1
- package/README.md +77 -29
- package/dist/es/index.js +153 -121
- package/dist/es/utils/index.js +37 -1
- package/dist/index.js +16 -2
- package/examples/events/README.md +3 -1
- package/package.json +78 -75
- package/rollup.config.js +9 -6
- package/src/.eslintrc +7 -3
- package/src/index.js +172 -133
- package/src/index.spec.js +212 -0
- package/src/utils/index.js +36 -2
- package/src/utils/index.spec.js +92 -29
- package/typings/.eslintrc +28 -0
- package/tslint.json +0 -101
package/src/index.spec.js
CHANGED
|
@@ -1159,6 +1159,20 @@ describe('useDropzone() hook', () => {
|
|
|
1159
1159
|
})
|
|
1160
1160
|
|
|
1161
1161
|
describe('onClick', () => {
|
|
1162
|
+
let currentShowOpenFilePicker;
|
|
1163
|
+
|
|
1164
|
+
beforeEach(() => {
|
|
1165
|
+
currentShowOpenFilePicker = window.showOpenFilePicker
|
|
1166
|
+
})
|
|
1167
|
+
|
|
1168
|
+
afterEach(() => {
|
|
1169
|
+
if (currentShowOpenFilePicker) {
|
|
1170
|
+
window.showOpenFilePicker = currentShowOpenFilePicker
|
|
1171
|
+
} else {
|
|
1172
|
+
delete window.showOpenFilePicker
|
|
1173
|
+
}
|
|
1174
|
+
})
|
|
1175
|
+
|
|
1162
1176
|
it('should proxy the click event to the input', () => {
|
|
1163
1177
|
const activeRef = createRef()
|
|
1164
1178
|
const active = <span ref={activeRef}>I am active</span>
|
|
@@ -1303,6 +1317,185 @@ describe('useDropzone() hook', () => {
|
|
|
1303
1317
|
jest.useRealTimers()
|
|
1304
1318
|
isIeOrEdgeSpy.mockClear()
|
|
1305
1319
|
})
|
|
1320
|
+
|
|
1321
|
+
it('should use showOpenFilePicker() if supported and not trigger click on input', async () => {
|
|
1322
|
+
const activeRef = createRef()
|
|
1323
|
+
const active = <span ref={activeRef}>I am active</span>
|
|
1324
|
+
const onClickSpy = jest.spyOn(HTMLInputElement.prototype, 'click')
|
|
1325
|
+
|
|
1326
|
+
const handlers = files.map(f => createFileSystemFileHandle(f))
|
|
1327
|
+
const thenable = createThenable()
|
|
1328
|
+
const showOpenFilePickerMock = jest.fn().mockReturnValue(thenable.promise)
|
|
1329
|
+
|
|
1330
|
+
window.showOpenFilePicker = showOpenFilePickerMock
|
|
1331
|
+
|
|
1332
|
+
const onDropSpy = jest.fn()
|
|
1333
|
+
const onFileDialogOpenSpy = jest.fn()
|
|
1334
|
+
|
|
1335
|
+
const ui = (
|
|
1336
|
+
<Dropzone
|
|
1337
|
+
onDrop={onDropSpy}
|
|
1338
|
+
onFileDialogOpen={onFileDialogOpenSpy}
|
|
1339
|
+
accept="application/pdf"
|
|
1340
|
+
multiple
|
|
1341
|
+
>
|
|
1342
|
+
{({ getRootProps, getInputProps, isFileDialogActive }) => (
|
|
1343
|
+
<div {...getRootProps()}>
|
|
1344
|
+
<input {...getInputProps()} />
|
|
1345
|
+
{isFileDialogActive && active}
|
|
1346
|
+
</div>
|
|
1347
|
+
)}
|
|
1348
|
+
</Dropzone>
|
|
1349
|
+
)
|
|
1350
|
+
|
|
1351
|
+
const { container, rerender } = render(ui)
|
|
1352
|
+
|
|
1353
|
+
const dropzone = container.querySelector('div')
|
|
1354
|
+
|
|
1355
|
+
fireEvent.click(dropzone)
|
|
1356
|
+
|
|
1357
|
+
await flushPromises(rerender, ui)
|
|
1358
|
+
|
|
1359
|
+
expect(activeRef.current).not.toBeNull()
|
|
1360
|
+
expect(dropzone).toContainElement(activeRef.current)
|
|
1361
|
+
expect(onFileDialogOpenSpy).toHaveBeenCalled()
|
|
1362
|
+
|
|
1363
|
+
thenable.done(handlers)
|
|
1364
|
+
await flushPromises(rerender, ui)
|
|
1365
|
+
|
|
1366
|
+
expect(activeRef.current).toBeNull() // We expect the dialog to be closed at this point
|
|
1367
|
+
expect(dropzone).not.toContainElement(activeRef.current)
|
|
1368
|
+
expect(onClickSpy).not.toHaveBeenCalled()
|
|
1369
|
+
expect(showOpenFilePickerMock).toHaveBeenCalledWith({
|
|
1370
|
+
multiple: true,
|
|
1371
|
+
types: [{
|
|
1372
|
+
description: 'everything',
|
|
1373
|
+
accept: {'application/pdf': []}
|
|
1374
|
+
}]
|
|
1375
|
+
})
|
|
1376
|
+
expect(onDropSpy).toHaveBeenCalledWith(files, [], null)
|
|
1377
|
+
})
|
|
1378
|
+
|
|
1379
|
+
test('if showOpenFilePicker() is supported it should work without the <input>', async () => {
|
|
1380
|
+
const activeRef = createRef()
|
|
1381
|
+
const active = <span ref={activeRef}>I am active</span>
|
|
1382
|
+
|
|
1383
|
+
const handlers = files.map(f => createFileSystemFileHandle(f))
|
|
1384
|
+
const showOpenFilePickerMock = jest.fn().mockReturnValue(Promise.resolve(handlers))
|
|
1385
|
+
|
|
1386
|
+
window.showOpenFilePicker = showOpenFilePickerMock
|
|
1387
|
+
|
|
1388
|
+
const onDropSpy = jest.fn()
|
|
1389
|
+
const onFileDialogOpenSpy = jest.fn()
|
|
1390
|
+
|
|
1391
|
+
const ui = (
|
|
1392
|
+
<Dropzone onDrop={onDropSpy} onFileDialogOpen={onFileDialogOpenSpy}>
|
|
1393
|
+
{({ getRootProps, isFileDialogActive }) => (
|
|
1394
|
+
<div {...getRootProps()}>
|
|
1395
|
+
{isFileDialogActive && active}
|
|
1396
|
+
</div>
|
|
1397
|
+
)}
|
|
1398
|
+
</Dropzone>
|
|
1399
|
+
)
|
|
1400
|
+
|
|
1401
|
+
const { container, rerender } = render(ui)
|
|
1402
|
+
|
|
1403
|
+
const dropzone = container.querySelector('div')
|
|
1404
|
+
|
|
1405
|
+
fireEvent.click(dropzone)
|
|
1406
|
+
await flushPromises(rerender, ui)
|
|
1407
|
+
const ref = activeRef.current
|
|
1408
|
+
expect(ref).toBeNull() // We expect the dialog to be closed at this point
|
|
1409
|
+
expect(dropzone).not.toContainElement(ref)
|
|
1410
|
+
expect(showOpenFilePickerMock).toHaveBeenCalled()
|
|
1411
|
+
expect(onDropSpy).toHaveBeenCalledWith(files, [], null)
|
|
1412
|
+
expect(onFileDialogOpenSpy).toHaveBeenCalled()
|
|
1413
|
+
})
|
|
1414
|
+
|
|
1415
|
+
test('if showOpenFilePicker() is supported and the user cancels it should call onFileDialogCancel', async () => {
|
|
1416
|
+
const activeRef = createRef()
|
|
1417
|
+
const active = <span ref={activeRef}>I am active</span>
|
|
1418
|
+
|
|
1419
|
+
const showOpenFilePickerMock = jest.fn().mockReturnValue(Promise.reject(new DOMException("user aborted request", "AbortError")))
|
|
1420
|
+
|
|
1421
|
+
window.showOpenFilePicker = showOpenFilePickerMock
|
|
1422
|
+
|
|
1423
|
+
const onDropSpy = jest.fn()
|
|
1424
|
+
const onFileDialogCancelSpy = jest.fn()
|
|
1425
|
+
|
|
1426
|
+
const ui = (
|
|
1427
|
+
<Dropzone onDrop={onDropSpy} onFileDialogCancel={onFileDialogCancelSpy}>
|
|
1428
|
+
{({ getRootProps, isFileDialogActive }) => (
|
|
1429
|
+
<div {...getRootProps()}>
|
|
1430
|
+
{isFileDialogActive && active}
|
|
1431
|
+
</div>
|
|
1432
|
+
)}
|
|
1433
|
+
</Dropzone>
|
|
1434
|
+
)
|
|
1435
|
+
|
|
1436
|
+
const { container, rerender } = render(ui)
|
|
1437
|
+
|
|
1438
|
+
const dropzone = container.querySelector('div')
|
|
1439
|
+
|
|
1440
|
+
fireEvent.click(dropzone)
|
|
1441
|
+
await flushPromises(rerender, ui)
|
|
1442
|
+
const ref = activeRef.current
|
|
1443
|
+
expect(ref).toBeNull() // We expect the dialog to be closed at this point
|
|
1444
|
+
expect(dropzone).not.toContainElement(ref)
|
|
1445
|
+
expect(showOpenFilePickerMock).toHaveBeenCalled()
|
|
1446
|
+
expect(onDropSpy).not.toHaveBeenCalled()
|
|
1447
|
+
expect(onFileDialogCancelSpy).toHaveBeenCalled()
|
|
1448
|
+
})
|
|
1449
|
+
|
|
1450
|
+
test('window focus evt is not bound if showOpenFilePicker() is supported', async () => {
|
|
1451
|
+
jest.useFakeTimers()
|
|
1452
|
+
|
|
1453
|
+
const activeRef = createRef()
|
|
1454
|
+
const active = <span ref={activeRef}>I am active</span>
|
|
1455
|
+
const onFileDialogCancelSpy = jest.fn()
|
|
1456
|
+
|
|
1457
|
+
const thenable = createThenable()
|
|
1458
|
+
const showOpenFilePickerMock = jest.fn().mockReturnValue(thenable.promise)
|
|
1459
|
+
|
|
1460
|
+
window.showOpenFilePicker = showOpenFilePickerMock
|
|
1461
|
+
|
|
1462
|
+
const ui = (
|
|
1463
|
+
<Dropzone onFileDialogCancel={onFileDialogCancelSpy} noClick>
|
|
1464
|
+
{({ getRootProps, isFileDialogActive, open }) => (
|
|
1465
|
+
<div {...getRootProps()}>
|
|
1466
|
+
{isFileDialogActive && active}
|
|
1467
|
+
<button type="button" onClick={open}>
|
|
1468
|
+
Open
|
|
1469
|
+
</button>
|
|
1470
|
+
</div>
|
|
1471
|
+
)}
|
|
1472
|
+
</Dropzone>
|
|
1473
|
+
)
|
|
1474
|
+
|
|
1475
|
+
const { container, rerender } = render(ui)
|
|
1476
|
+
|
|
1477
|
+
const dropzone = container.querySelector('div')
|
|
1478
|
+
const btn = container.querySelector('button')
|
|
1479
|
+
|
|
1480
|
+
btn.click()
|
|
1481
|
+
drainTimers()
|
|
1482
|
+
await flushPromises(rerender, ui)
|
|
1483
|
+
|
|
1484
|
+
const ref = activeRef.current
|
|
1485
|
+
expect(ref).not.toBeNull()
|
|
1486
|
+
expect(dropzone).toContainElement(ref)
|
|
1487
|
+
|
|
1488
|
+
thenable.cancel(new DOMException('user aborted request', 'AbortError'))
|
|
1489
|
+
|
|
1490
|
+
dispatchEvt(document.body, 'focus')
|
|
1491
|
+
drainTimers()
|
|
1492
|
+
await flushPromises(rerender, ui)
|
|
1493
|
+
|
|
1494
|
+
expect(onFileDialogCancelSpy).toHaveBeenCalledTimes(1)
|
|
1495
|
+
expect(dropzone).not.toContainElement(ref)
|
|
1496
|
+
|
|
1497
|
+
jest.useRealTimers()
|
|
1498
|
+
})
|
|
1306
1499
|
})
|
|
1307
1500
|
|
|
1308
1501
|
describe('onKeyDown', () => {
|
|
@@ -2854,6 +3047,10 @@ function dispatchEvt(node, type, data) {
|
|
|
2854
3047
|
fireEvent(node, event)
|
|
2855
3048
|
}
|
|
2856
3049
|
|
|
3050
|
+
function createFileSystemFileHandle(file) {
|
|
3051
|
+
return {getFile: () => Promise.resolve(file)}
|
|
3052
|
+
}
|
|
3053
|
+
|
|
2857
3054
|
function createFile(name, size, type) {
|
|
2858
3055
|
const file = new File([], name, { type })
|
|
2859
3056
|
Object.defineProperty(file, 'size', {
|
|
@@ -2863,3 +3060,18 @@ function createFile(name, size, type) {
|
|
|
2863
3060
|
})
|
|
2864
3061
|
return file
|
|
2865
3062
|
}
|
|
3063
|
+
|
|
3064
|
+
function createThenable() {
|
|
3065
|
+
let done, cancel;
|
|
3066
|
+
|
|
3067
|
+
const promise = new Promise((resolve, reject) => {
|
|
3068
|
+
done = resolve
|
|
3069
|
+
cancel = reject
|
|
3070
|
+
})
|
|
3071
|
+
|
|
3072
|
+
return {
|
|
3073
|
+
promise,
|
|
3074
|
+
done,
|
|
3075
|
+
cancel
|
|
3076
|
+
}
|
|
3077
|
+
}
|
package/src/utils/index.js
CHANGED
|
@@ -66,8 +66,8 @@ function isDefined(value) {
|
|
|
66
66
|
return value !== undefined && value !== null
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
export function allFilesAccepted({
|
|
70
|
-
if ((!multiple && files.length > 1) || (multiple && maxFiles >= 1 &&
|
|
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
|
+
}
|
package/src/utils/index.spec.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
+
}
|
|
@@ -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
|
+
}
|
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
|
-
}
|