@instructure/ui-file-drop 8.25.0 → 8.25.1-snapshot-7
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/CHANGELOG.md +8 -0
- package/es/FileDrop/index.js +61 -69
- package/es/FileDrop/props.js +0 -98
- package/es/FileDrop/utils/getEventFiles.js +8 -6
- package/lib/FileDrop/index.js +63 -70
- package/lib/FileDrop/props.js +0 -98
- package/lib/FileDrop/utils/getEventFiles.js +8 -6
- package/package.json +22 -22
- package/src/FileDrop/index.tsx +75 -106
- package/src/FileDrop/props.ts +91 -76
- package/src/FileDrop/utils/accepts.ts +4 -4
- package/src/FileDrop/utils/getEventFiles.ts +13 -8
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/FileDrop/index.d.ts +48 -43
- package/types/FileDrop/index.d.ts.map +1 -1
- package/types/FileDrop/props.d.ts +89 -8
- package/types/FileDrop/props.d.ts.map +1 -1
- package/types/FileDrop/utils/accepts.d.ts +2 -2
- package/types/FileDrop/utils/accepts.d.ts.map +1 -1
- package/types/FileDrop/utils/getEventFiles.d.ts +2 -1
- package/types/FileDrop/utils/getEventFiles.d.ts.map +1 -1
package/src/FileDrop/index.tsx
CHANGED
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
* SOFTWARE.
|
|
23
23
|
*/
|
|
24
24
|
/** @jsx jsx */
|
|
25
|
-
import { Component } from 'react'
|
|
25
|
+
import React, { Component } from 'react'
|
|
26
26
|
import keycode from 'keycode'
|
|
27
|
-
|
|
28
27
|
import { FormFieldMessages } from '@instructure/ui-form-field'
|
|
28
|
+
import type { FormMessage } from '@instructure/ui-form-field'
|
|
29
29
|
import { View } from '@instructure/ui-view'
|
|
30
30
|
import { testable } from '@instructure/ui-testable'
|
|
31
31
|
import {
|
|
@@ -34,7 +34,6 @@ import {
|
|
|
34
34
|
getInteraction,
|
|
35
35
|
withDeterministicId
|
|
36
36
|
} from '@instructure/ui-react-utils'
|
|
37
|
-
import { isEdge } from '@instructure/ui-utils'
|
|
38
37
|
|
|
39
38
|
import { accepts, getAcceptList } from './utils/accepts'
|
|
40
39
|
import { getEventFiles } from './utils/getEventFiles'
|
|
@@ -46,26 +45,15 @@ import generateComponentTheme from './theme'
|
|
|
46
45
|
import { propTypes, allowedProps } from './props'
|
|
47
46
|
import type { FileDropProps, FileDropState, FileDropStyleProps } from './props'
|
|
48
47
|
|
|
49
|
-
function keyEventIsClickButton(e:
|
|
48
|
+
function keyEventIsClickButton(e: React.KeyboardEvent) {
|
|
50
49
|
return e.keyCode === keycode.codes.space || e.keyCode === keycode.codes.enter
|
|
51
50
|
}
|
|
52
51
|
|
|
53
|
-
// Used try-catch due to missing document/navigator references in Jenkins
|
|
54
|
-
function isBrowserMS() {
|
|
55
|
-
let result = false
|
|
56
|
-
try {
|
|
57
|
-
// @ts-expect-error ts-migrate(2551) FIXME: Property 'documentMode' does not exist on type 'Do... Remove this comment to see the full error message
|
|
58
|
-
result = document.documentMode || isEdge
|
|
59
|
-
} catch (e) {} // eslint-disable-line no-empty
|
|
60
|
-
return result
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const IS_MS = isBrowserMS()
|
|
64
|
-
|
|
65
52
|
/**
|
|
66
53
|
---
|
|
67
54
|
category: components
|
|
68
55
|
---
|
|
56
|
+
@tsProps
|
|
69
57
|
**/
|
|
70
58
|
@withDeterministicId()
|
|
71
59
|
@withStyle(generateStyle, generateComponentTheme)
|
|
@@ -76,20 +64,7 @@ class FileDrop extends Component<FileDropProps, FileDropState> {
|
|
|
76
64
|
static propTypes = propTypes
|
|
77
65
|
static allowedProps = allowedProps
|
|
78
66
|
static defaultProps = {
|
|
79
|
-
|
|
80
|
-
onClick: function (e: any) {},
|
|
81
|
-
// @ts-expect-error ts-migrate(6133) FIXME: 'accepted' is declared but its value is never read... Remove this comment to see the full error message
|
|
82
|
-
onDrop: function (accepted: any, rejected: any, e: any) {},
|
|
83
|
-
// @ts-expect-error ts-migrate(6133) FIXME: 'accepted' is declared but its value is never read... Remove this comment to see the full error message
|
|
84
|
-
onDropAccepted: function (accepted: any, e: any) {},
|
|
85
|
-
// @ts-expect-error ts-migrate(6133) FIXME: 'rejected' is declared but its value is never read... Remove this comment to see the full error message
|
|
86
|
-
onDropRejected: function (rejected: any, e: any) {},
|
|
87
|
-
// @ts-expect-error ts-migrate(6133) FIXME: 'e' is declared but its value is never read.
|
|
88
|
-
onDragEnter: function (e: any) {},
|
|
89
|
-
// @ts-expect-error ts-migrate(6133) FIXME: 'e' is declared but its value is never read.
|
|
90
|
-
onDragOver: function (e: any) {},
|
|
91
|
-
// @ts-expect-error ts-migrate(6133) FIXME: 'e' is declared but its value is never read.
|
|
92
|
-
onDragLeave: function (e: any) {},
|
|
67
|
+
onClick: function (_e: React.MouseEvent) {},
|
|
93
68
|
shouldEnablePreview: false,
|
|
94
69
|
shouldAllowMultiple: false,
|
|
95
70
|
shouldAllowRepeats: true,
|
|
@@ -106,11 +81,17 @@ class FileDrop extends Component<FileDropProps, FileDropState> {
|
|
|
106
81
|
this.messagesId = props.deterministicId!('FileDrop-messages')
|
|
107
82
|
}
|
|
108
83
|
componentDidMount() {
|
|
109
|
-
|
|
84
|
+
this.props.makeStyles?.(this.makeStyleProps())
|
|
110
85
|
}
|
|
111
86
|
|
|
112
87
|
componentDidUpdate() {
|
|
113
|
-
|
|
88
|
+
this.props.makeStyles?.(this.makeStyleProps())
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
convertToFile(fileLikeItem: DataTransferItem | File) {
|
|
92
|
+
if (fileLikeItem instanceof DataTransferItem)
|
|
93
|
+
return fileLikeItem.getAsFile()
|
|
94
|
+
else return fileLikeItem
|
|
114
95
|
}
|
|
115
96
|
|
|
116
97
|
makeStyleProps = (): FileDropStyleProps => {
|
|
@@ -130,7 +111,7 @@ class FileDrop extends Component<FileDropProps, FileDropState> {
|
|
|
130
111
|
}
|
|
131
112
|
|
|
132
113
|
enterCounter = 0
|
|
133
|
-
fileInputEl = null
|
|
114
|
+
fileInputEl: HTMLInputElement | null = null
|
|
134
115
|
defaultId: string | null = null
|
|
135
116
|
messagesId = ''
|
|
136
117
|
|
|
@@ -145,9 +126,7 @@ class FileDrop extends Component<FileDropProps, FileDropState> {
|
|
|
145
126
|
}
|
|
146
127
|
|
|
147
128
|
get hasMessages() {
|
|
148
|
-
return
|
|
149
|
-
(this.props as any).messages && (this.props as any).messages.length > 0
|
|
150
|
-
)
|
|
129
|
+
return this.props.messages && this.props.messages.length > 0
|
|
151
130
|
}
|
|
152
131
|
|
|
153
132
|
get interaction() {
|
|
@@ -155,28 +134,32 @@ class FileDrop extends Component<FileDropProps, FileDropState> {
|
|
|
155
134
|
}
|
|
156
135
|
|
|
157
136
|
get invalid() {
|
|
158
|
-
return (
|
|
159
|
-
this.
|
|
160
|
-
(this.props as any).messages.findIndex((message: any) => {
|
|
137
|
+
return (this.hasMessages &&
|
|
138
|
+
this.props.messages!.findIndex((message: FormMessage) => {
|
|
161
139
|
return message.type === 'error'
|
|
162
|
-
}) >= 0
|
|
163
|
-
)
|
|
140
|
+
}) >= 0) as boolean
|
|
164
141
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
142
|
+
getDataTransferItems(
|
|
143
|
+
e: React.ChangeEvent | React.DragEvent,
|
|
144
|
+
shouldEnablePreview?: boolean
|
|
145
|
+
): Array<File> {
|
|
146
|
+
let list: Array<File> = []
|
|
147
|
+
Array.from(getEventFiles(e, this.fileInputEl)).forEach((file) => {
|
|
148
|
+
const fileObj = this.convertToFile(file)
|
|
149
|
+
if (fileObj) list.push(fileObj)
|
|
150
|
+
})
|
|
168
151
|
if (list.length > 1) {
|
|
169
|
-
list =
|
|
152
|
+
list = this.props.shouldAllowMultiple ? list : [list[0]]
|
|
170
153
|
}
|
|
171
154
|
if (shouldEnablePreview) {
|
|
172
|
-
return list.map((file:
|
|
155
|
+
return list.map((file: File) =>
|
|
173
156
|
Object.assign(file, { preview: window.URL.createObjectURL(file) })
|
|
174
157
|
)
|
|
175
158
|
}
|
|
176
159
|
return list
|
|
177
160
|
}
|
|
178
161
|
|
|
179
|
-
handleDragEnter = (e:
|
|
162
|
+
handleDragEnter = (e: React.DragEvent) => {
|
|
180
163
|
e.preventDefault()
|
|
181
164
|
// Count the dropzone and any children that are entered.
|
|
182
165
|
this.enterCounter += 1
|
|
@@ -184,16 +167,15 @@ class FileDrop extends Component<FileDropProps, FileDropState> {
|
|
|
184
167
|
if (this.enterCounter > 1) {
|
|
185
168
|
return
|
|
186
169
|
}
|
|
187
|
-
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
|
188
170
|
const allFilesAccepted = this.allFilesAccepted(this.getDataTransferItems(e))
|
|
189
171
|
this.setState({
|
|
190
172
|
isDragAccepted: allFilesAccepted,
|
|
191
173
|
isDragRejected: !allFilesAccepted
|
|
192
174
|
})
|
|
193
|
-
|
|
175
|
+
this.props.onDragEnter?.(e)
|
|
194
176
|
}
|
|
195
177
|
|
|
196
|
-
handleDragOver = (e:
|
|
178
|
+
handleDragOver = (e: React.DragEvent) => {
|
|
197
179
|
e.preventDefault()
|
|
198
180
|
e.stopPropagation()
|
|
199
181
|
try {
|
|
@@ -202,11 +184,11 @@ class FileDrop extends Component<FileDropProps, FileDropState> {
|
|
|
202
184
|
} catch (err) {
|
|
203
185
|
// continue regardless of error
|
|
204
186
|
}
|
|
205
|
-
|
|
187
|
+
this.props.onDragOver?.(e)
|
|
206
188
|
return false
|
|
207
189
|
}
|
|
208
190
|
|
|
209
|
-
handleDragLeave = (e:
|
|
191
|
+
handleDragLeave = (e: React.DragEvent) => {
|
|
210
192
|
e.preventDefault()
|
|
211
193
|
this.enterCounter -= 1
|
|
212
194
|
// Only deactivate once the dropzone and all children was left
|
|
@@ -217,14 +199,19 @@ class FileDrop extends Component<FileDropProps, FileDropState> {
|
|
|
217
199
|
isDragAccepted: false,
|
|
218
200
|
isDragRejected: false
|
|
219
201
|
})
|
|
220
|
-
|
|
202
|
+
this.props.onDragLeave?.(e)
|
|
221
203
|
}
|
|
222
204
|
|
|
223
|
-
parseFiles(fileList:
|
|
224
|
-
const accepted:
|
|
225
|
-
const rejected:
|
|
226
|
-
fileList.forEach((file:
|
|
227
|
-
|
|
205
|
+
parseFiles(fileList: Array<DataTransferItem | File>) {
|
|
206
|
+
const accepted: typeof fileList = []
|
|
207
|
+
const rejected: typeof fileList = []
|
|
208
|
+
fileList.forEach((file: DataTransferItem | File) => {
|
|
209
|
+
const fileObj = this.convertToFile(file)
|
|
210
|
+
if (
|
|
211
|
+
fileObj &&
|
|
212
|
+
this.fileAccepted(fileObj) &&
|
|
213
|
+
this.fileMatchSize(fileObj)
|
|
214
|
+
) {
|
|
228
215
|
accepted.push(file)
|
|
229
216
|
} else {
|
|
230
217
|
rejected.push(file)
|
|
@@ -233,21 +220,18 @@ class FileDrop extends Component<FileDropProps, FileDropState> {
|
|
|
233
220
|
return [accepted, rejected]
|
|
234
221
|
}
|
|
235
222
|
|
|
236
|
-
handleChange = (e:
|
|
223
|
+
handleChange = (e: React.ChangeEvent | React.DragEvent) => {
|
|
237
224
|
const { onDrop, onDropAccepted, onDropRejected, shouldEnablePreview } =
|
|
238
225
|
this.props
|
|
239
226
|
const fileList = this.getDataTransferItems(e, shouldEnablePreview)
|
|
240
227
|
const [accepted, rejected] = this.parseFiles(fileList)
|
|
241
228
|
e.preventDefault()
|
|
242
229
|
this.enterCounter = 0
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
if (rejected.length > 0) {
|
|
246
|
-
// @ts-expect-error ts-migrate(2722) FIXME: Cannot invoke an object which is possibly 'undefined'.
|
|
230
|
+
onDrop && onDrop(accepted, rejected, e as React.DragEvent)
|
|
231
|
+
if (rejected.length > 0 && onDropRejected) {
|
|
247
232
|
onDropRejected(rejected, e)
|
|
248
233
|
}
|
|
249
|
-
if (accepted.length > 0) {
|
|
250
|
-
// @ts-expect-error ts-migrate(2722) FIXME: Cannot invoke an object which is possibly 'undefined'.
|
|
234
|
+
if (accepted.length > 0 && onDropAccepted) {
|
|
251
235
|
onDropAccepted(accepted, e)
|
|
252
236
|
}
|
|
253
237
|
this.setState({
|
|
@@ -257,24 +241,22 @@ class FileDrop extends Component<FileDropProps, FileDropState> {
|
|
|
257
241
|
})
|
|
258
242
|
}
|
|
259
243
|
|
|
260
|
-
fileAccepted = (file:
|
|
261
|
-
return accepts(file,
|
|
244
|
+
fileAccepted = (file: File) => {
|
|
245
|
+
if (this.props.accept) return accepts(file, this.props.accept)
|
|
246
|
+
else return true
|
|
262
247
|
}
|
|
263
248
|
|
|
264
|
-
fileMatchSize(file:
|
|
265
|
-
return
|
|
266
|
-
file.size <= (this.props as any).maxSize &&
|
|
267
|
-
file.size >= (this.props as any).minSize
|
|
268
|
-
)
|
|
249
|
+
fileMatchSize(file: File) {
|
|
250
|
+
return file.size <= this.props.maxSize! && file.size >= this.props.minSize!
|
|
269
251
|
}
|
|
270
252
|
|
|
271
|
-
allFilesAccepted(files:
|
|
253
|
+
allFilesAccepted(files: Array<File>) {
|
|
272
254
|
return files.every(this.fileAccepted)
|
|
273
255
|
}
|
|
274
256
|
|
|
275
257
|
acceptStr() {
|
|
276
258
|
const { accept } = this.props
|
|
277
|
-
return accept ? getAcceptList(accept).join(',') :
|
|
259
|
+
return accept ? getAcceptList(accept).join(',') : undefined
|
|
278
260
|
}
|
|
279
261
|
|
|
280
262
|
renderLabel() {
|
|
@@ -286,7 +268,7 @@ class FileDrop extends Component<FileDropProps, FileDropState> {
|
|
|
286
268
|
})
|
|
287
269
|
}
|
|
288
270
|
|
|
289
|
-
handleRef = (el:
|
|
271
|
+
handleRef = (el: HTMLInputElement) => {
|
|
290
272
|
this.fileInputEl = el
|
|
291
273
|
}
|
|
292
274
|
|
|
@@ -304,40 +286,27 @@ class FileDrop extends Component<FileDropProps, FileDropState> {
|
|
|
304
286
|
})
|
|
305
287
|
}
|
|
306
288
|
|
|
307
|
-
handleClick = (e:
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
|
311
|
-
this.fileInputEl.value = null
|
|
289
|
+
handleClick = (e: React.MouseEvent) => {
|
|
290
|
+
if (this.fileInputEl!.value && this.props.shouldAllowRepeats) {
|
|
291
|
+
this.fileInputEl!.value = null as unknown as string
|
|
312
292
|
}
|
|
313
293
|
// focus the input (because FF won't)
|
|
314
|
-
|
|
315
|
-
this.
|
|
316
|
-
;(this.props as any).onClick(e)
|
|
294
|
+
this.fileInputEl?.focus()
|
|
295
|
+
this.props.onClick!(e)
|
|
317
296
|
this.setState({
|
|
318
297
|
isFileBrowserDisplayed: true
|
|
319
298
|
})
|
|
320
299
|
}
|
|
321
300
|
|
|
322
|
-
handleKeyDown = (e:
|
|
301
|
+
handleKeyDown = (e: React.KeyboardEvent) => {
|
|
323
302
|
if (this.state.isFocused && keyEventIsClickButton(e)) {
|
|
324
|
-
if (
|
|
325
|
-
|
|
326
|
-
this.fileInputEl.value = null
|
|
327
|
-
}
|
|
328
|
-
// This bit of logic is necessary for MS browsers but causes unwanted warnings in Firefox
|
|
329
|
-
// So we need to apply this logic only on MS browsers
|
|
330
|
-
/* istanbul ignore if */
|
|
331
|
-
if (IS_MS) {
|
|
332
|
-
e.stopPropagation()
|
|
333
|
-
e.preventDefault()
|
|
334
|
-
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
|
335
|
-
this.fileInputEl.click()
|
|
303
|
+
if (this.props.shouldAllowRepeats) {
|
|
304
|
+
this.fileInputEl!.value = null as unknown as string
|
|
336
305
|
}
|
|
337
306
|
}
|
|
338
307
|
}
|
|
339
308
|
|
|
340
|
-
handleKeyUp = (e:
|
|
309
|
+
handleKeyUp = (e: React.KeyboardEvent) => {
|
|
341
310
|
// This is to handle the case where ESC is pressed inside a Dialog so that
|
|
342
311
|
// closing the file browser dialog doesn't also close the Dialog.
|
|
343
312
|
if (e.keyCode === keycode.codes.esc && this.state.isFileBrowserDisplayed) {
|
|
@@ -361,7 +330,7 @@ class FileDrop extends Component<FileDropProps, FileDropState> {
|
|
|
361
330
|
onDropRejected,
|
|
362
331
|
...props
|
|
363
332
|
} = this.props
|
|
364
|
-
const id =
|
|
333
|
+
const id = this.props.id || this.defaultId!
|
|
365
334
|
const focusColor =
|
|
366
335
|
this.state.isDragRejected || this.invalid ? 'danger' : undefined
|
|
367
336
|
|
|
@@ -377,7 +346,7 @@ class FileDrop extends Component<FileDropProps, FileDropState> {
|
|
|
377
346
|
elementRef={this.handleElementRef}
|
|
378
347
|
>
|
|
379
348
|
<label
|
|
380
|
-
css={
|
|
349
|
+
css={this.props.styles?.fileDropLabel}
|
|
381
350
|
htmlFor={id}
|
|
382
351
|
onDragEnter={this.handleDragEnter}
|
|
383
352
|
onDragOver={this.handleDragOver}
|
|
@@ -392,8 +361,8 @@ class FileDrop extends Component<FileDropProps, FileDropState> {
|
|
|
392
361
|
focusColor={focusColor}
|
|
393
362
|
height={height}
|
|
394
363
|
>
|
|
395
|
-
<span css={
|
|
396
|
-
<span css={
|
|
364
|
+
<span css={this.props.styles?.fileDropLabelContent}>
|
|
365
|
+
<span css={this.props.styles?.fileDropLayout}>
|
|
397
366
|
<View height={height}>{this.renderLabel()}</View>
|
|
398
367
|
</span>
|
|
399
368
|
</span>
|
|
@@ -403,24 +372,24 @@ class FileDrop extends Component<FileDropProps, FileDropState> {
|
|
|
403
372
|
{...passthroughProps(props)}
|
|
404
373
|
onClick={this.handleClick}
|
|
405
374
|
type="file"
|
|
406
|
-
css={
|
|
375
|
+
css={this.props.styles?.fileDropInput}
|
|
407
376
|
id={id}
|
|
408
377
|
ref={this.handleRef}
|
|
409
378
|
onFocus={this.handleFocus}
|
|
410
379
|
onBlur={this.handleBlur}
|
|
411
380
|
onKeyDown={this.handleKeyDown}
|
|
412
381
|
onKeyUp={this.handleKeyUp}
|
|
413
|
-
multiple={
|
|
382
|
+
multiple={this.props.shouldAllowMultiple}
|
|
414
383
|
accept={this.acceptStr()}
|
|
415
384
|
onChange={this.handleChange}
|
|
416
|
-
aria-describedby={this.hasMessages ?
|
|
385
|
+
aria-describedby={this.hasMessages ? this.messagesId : undefined}
|
|
417
386
|
disabled={this.functionallyDisabled}
|
|
418
387
|
/>
|
|
419
388
|
{this.hasMessages ? (
|
|
420
389
|
<View display="block" margin="small 0 0">
|
|
421
390
|
<FormFieldMessages
|
|
422
|
-
id={
|
|
423
|
-
messages={
|
|
391
|
+
id={this.messagesId}
|
|
392
|
+
messages={this.props.messages}
|
|
424
393
|
/>
|
|
425
394
|
</View>
|
|
426
395
|
) : null}
|
package/src/FileDrop/props.ts
CHANGED
|
@@ -39,161 +39,176 @@ import type {
|
|
|
39
39
|
OtherHTMLAttributes
|
|
40
40
|
} from '@instructure/shared-types'
|
|
41
41
|
import type { WithDeterministicIdProps } from '@instructure/ui-react-utils'
|
|
42
|
-
|
|
43
|
-
type FileDropOwnProps = {
|
|
44
|
-
id?: string
|
|
45
|
-
renderLabel: ((...args: any[]) => any) | React.ReactNode
|
|
46
|
-
accept?: string | string[]
|
|
47
|
-
messages?: FormMessage[]
|
|
48
|
-
onClick?: (...args: any[]) => any
|
|
49
|
-
onDrop?: (...args: any[]) => any
|
|
50
|
-
onDropAccepted?: (...args: any[]) => any
|
|
51
|
-
onDropRejected?: (...args: any[]) => any
|
|
52
|
-
onDragEnter?: (...args: any[]) => any
|
|
53
|
-
onDragOver?: (...args: any[]) => any
|
|
54
|
-
onDragLeave?: (...args: any[]) => any
|
|
55
|
-
shouldEnablePreview?: boolean
|
|
56
|
-
shouldAllowMultiple?: boolean
|
|
57
|
-
shouldAllowRepeats?: boolean
|
|
58
|
-
maxSize?: number
|
|
59
|
-
minSize?: number
|
|
60
|
-
interaction?: 'enabled' | 'disabled' | 'readonly'
|
|
61
|
-
display?: 'block' | 'inline-block'
|
|
62
|
-
height?: string | number
|
|
63
|
-
width?: string | number
|
|
64
|
-
maxWidth?: string | number
|
|
65
|
-
minWidth?: string | number
|
|
66
|
-
margin?: Spacing
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
type FileDropState = {
|
|
42
|
+
type RenderLabelProps = {
|
|
70
43
|
isDragAccepted: boolean
|
|
71
44
|
isDragRejected: boolean
|
|
72
|
-
|
|
73
|
-
isFileBrowserDisplayed: boolean
|
|
45
|
+
interaction: boolean
|
|
74
46
|
}
|
|
75
|
-
|
|
76
|
-
type FileDropStyleProps = {
|
|
77
|
-
functionallyDisabled: boolean
|
|
78
|
-
visuallyDisabled: boolean
|
|
79
|
-
dragRejected: boolean
|
|
80
|
-
dragAccepted: boolean
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
type PropKeys = keyof FileDropOwnProps
|
|
84
|
-
|
|
85
|
-
type AllowedPropKeys = Readonly<Array<PropKeys>>
|
|
86
|
-
|
|
87
|
-
type FileDropProps = FileDropOwnProps &
|
|
88
|
-
WithStyleProps<FileDropTheme, FileDropStyle> &
|
|
89
|
-
OtherHTMLAttributes<FileDropOwnProps> & WithDeterministicIdProps
|
|
90
|
-
|
|
91
|
-
type FileDropStyle = ComponentStyle<
|
|
92
|
-
'fileDropLabel' | 'fileDropInput' | 'fileDropLabelContent' | 'fileDropLayout'
|
|
93
|
-
>
|
|
94
|
-
|
|
95
|
-
const propTypes: PropValidators<PropKeys> = {
|
|
47
|
+
type FileDropOwnProps = {
|
|
96
48
|
/**
|
|
97
49
|
* The id of the input (to link it to its label for a11y)
|
|
98
50
|
*/
|
|
99
|
-
id
|
|
51
|
+
id?: string
|
|
100
52
|
/**
|
|
101
53
|
* The content of FileDrop; can be a component or React node.
|
|
102
54
|
* Components receive `isDragAccepted` and `isDragRejected` as props.
|
|
103
55
|
*/
|
|
104
|
-
renderLabel:
|
|
56
|
+
renderLabel: ((props: RenderLabelProps) => React.ReactNode) | React.ReactNode
|
|
105
57
|
/**
|
|
106
58
|
* The mime media type/s or file extension/s allowed to be dropped inside
|
|
107
59
|
*/
|
|
108
|
-
accept
|
|
109
|
-
PropTypes.string,
|
|
110
|
-
PropTypes.arrayOf(PropTypes.string)
|
|
111
|
-
]),
|
|
60
|
+
accept?: string | string[]
|
|
112
61
|
/**
|
|
113
62
|
* object with shape: `{
|
|
114
63
|
* text: PropTypes.node,
|
|
115
64
|
* type: PropTypes.oneOf(['error', 'hint', 'success', 'screenreader-only'])
|
|
116
65
|
* }`
|
|
117
66
|
*/
|
|
118
|
-
messages
|
|
67
|
+
messages?: FormMessage[]
|
|
119
68
|
/**
|
|
120
69
|
* Called when clicking on drop area to select files to upload
|
|
121
70
|
*/
|
|
122
|
-
onClick:
|
|
71
|
+
onClick?: (e: React.MouseEvent) => void
|
|
123
72
|
/**
|
|
124
73
|
* Called when dropping files or when file dialog window exits successfully
|
|
125
74
|
*/
|
|
126
|
-
onDrop
|
|
75
|
+
onDrop?: (
|
|
76
|
+
accepted: ArrayLike<DataTransferItem | File>,
|
|
77
|
+
rejected: ArrayLike<DataTransferItem | File>,
|
|
78
|
+
e: React.DragEvent
|
|
79
|
+
) => void
|
|
127
80
|
/**
|
|
128
81
|
* Called when dropping allowed files
|
|
129
82
|
*/
|
|
130
|
-
onDropAccepted
|
|
83
|
+
onDropAccepted?: (
|
|
84
|
+
accepted: ArrayLike<DataTransferItem | File>,
|
|
85
|
+
e: React.DragEvent | React.ChangeEvent
|
|
86
|
+
) => void
|
|
131
87
|
/**
|
|
132
88
|
* Called when dropping rejected files
|
|
133
89
|
*/
|
|
134
|
-
onDropRejected
|
|
90
|
+
onDropRejected?: (
|
|
91
|
+
rejected: ArrayLike<DataTransferItem | File>,
|
|
92
|
+
e: React.DragEvent | React.ChangeEvent
|
|
93
|
+
) => void
|
|
135
94
|
/**
|
|
136
95
|
* Called when dragging files
|
|
137
96
|
* and passing through FileDrop's content for the first time
|
|
138
97
|
*/
|
|
139
|
-
onDragEnter:
|
|
98
|
+
onDragEnter?: (e: React.DragEvent) => void
|
|
140
99
|
/**
|
|
141
100
|
* Called when dragging files and passing through FileDrop's content
|
|
142
101
|
*/
|
|
143
|
-
onDragOver:
|
|
102
|
+
onDragOver?: (e: React.DragEvent) => void
|
|
144
103
|
/**
|
|
145
104
|
* Called when dragging files and leaving FileDrop's content
|
|
146
105
|
*/
|
|
147
|
-
onDragLeave:
|
|
106
|
+
onDragLeave?: (e: React.DragEvent) => void
|
|
148
107
|
/**
|
|
149
108
|
* Flag to use window.URL.createObjectURL for each dropped file and pass it through file.preview
|
|
150
109
|
*/
|
|
151
|
-
shouldEnablePreview
|
|
110
|
+
shouldEnablePreview?: boolean
|
|
152
111
|
/**
|
|
153
112
|
* Flag to allow multiple files to drop at once
|
|
154
113
|
*/
|
|
155
|
-
shouldAllowMultiple
|
|
114
|
+
shouldAllowMultiple?: boolean
|
|
156
115
|
/**
|
|
157
116
|
* Flag to allow upload of the same file more than once
|
|
158
117
|
*/
|
|
159
|
-
shouldAllowRepeats
|
|
118
|
+
shouldAllowRepeats?: boolean
|
|
160
119
|
/**
|
|
161
120
|
* the maximum file size allowed
|
|
162
121
|
*/
|
|
163
|
-
maxSize
|
|
122
|
+
maxSize?: number
|
|
164
123
|
/**
|
|
165
124
|
* the minimum file size allowed
|
|
166
125
|
*/
|
|
167
|
-
minSize
|
|
126
|
+
minSize?: number
|
|
168
127
|
/**
|
|
169
128
|
* Specifies if interaction with the input is enabled, disabled, or readonly.
|
|
170
129
|
*/
|
|
171
|
-
interaction
|
|
130
|
+
interaction?: 'enabled' | 'disabled' | 'readonly'
|
|
172
131
|
/**
|
|
173
132
|
* Set the CSS `display` property on FileInput's outermost element
|
|
174
133
|
*/
|
|
175
|
-
display
|
|
134
|
+
display?: 'block' | 'inline-block'
|
|
176
135
|
/**
|
|
177
136
|
* Set the CSS `height` property on FileInput's outermost element
|
|
178
137
|
*/
|
|
179
|
-
height
|
|
138
|
+
height?: string | number
|
|
180
139
|
/**
|
|
181
140
|
* Set the CSS `width` property on FileInput's outermost element
|
|
182
141
|
*/
|
|
183
|
-
width
|
|
142
|
+
width?: string | number
|
|
184
143
|
/**
|
|
185
144
|
* Set the CSS `maxWidth` property on FileInput's outermost element
|
|
186
145
|
*/
|
|
187
|
-
maxWidth
|
|
146
|
+
maxWidth?: string | number
|
|
188
147
|
/**
|
|
189
148
|
* Set the CSS `minWidth` property on FileInput's outermost element
|
|
190
149
|
*/
|
|
191
|
-
minWidth
|
|
150
|
+
minWidth?: string | number
|
|
192
151
|
/**
|
|
193
152
|
* Valid values are 0, none, auto, xxx-small, xx-small, x-small, small,
|
|
194
153
|
* medium, large, x-large, xx-large. Apply these values via familiar
|
|
195
154
|
* CSS-like shorthand. For example: margin="small auto large".
|
|
196
155
|
*/
|
|
156
|
+
margin?: Spacing
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
type FileDropState = {
|
|
160
|
+
isDragAccepted: boolean
|
|
161
|
+
isDragRejected: boolean
|
|
162
|
+
isFocused: boolean
|
|
163
|
+
isFileBrowserDisplayed: boolean
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
type FileDropStyleProps = {
|
|
167
|
+
functionallyDisabled: boolean
|
|
168
|
+
visuallyDisabled: boolean
|
|
169
|
+
dragRejected: boolean
|
|
170
|
+
dragAccepted: boolean
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
type PropKeys = keyof FileDropOwnProps
|
|
174
|
+
|
|
175
|
+
type AllowedPropKeys = Readonly<Array<PropKeys>>
|
|
176
|
+
|
|
177
|
+
type FileDropProps = FileDropOwnProps &
|
|
178
|
+
WithStyleProps<FileDropTheme, FileDropStyle> &
|
|
179
|
+
OtherHTMLAttributes<FileDropOwnProps> &
|
|
180
|
+
WithDeterministicIdProps
|
|
181
|
+
|
|
182
|
+
type FileDropStyle = ComponentStyle<
|
|
183
|
+
'fileDropLabel' | 'fileDropInput' | 'fileDropLabelContent' | 'fileDropLayout'
|
|
184
|
+
>
|
|
185
|
+
|
|
186
|
+
const propTypes: PropValidators<PropKeys> = {
|
|
187
|
+
id: PropTypes.string,
|
|
188
|
+
renderLabel: PropTypes.oneOfType([PropTypes.func, PropTypes.node]).isRequired,
|
|
189
|
+
accept: PropTypes.oneOfType([
|
|
190
|
+
PropTypes.string,
|
|
191
|
+
PropTypes.arrayOf(PropTypes.string)
|
|
192
|
+
]),
|
|
193
|
+
messages: PropTypes.arrayOf(FormPropTypes.message),
|
|
194
|
+
onClick: PropTypes.func,
|
|
195
|
+
onDrop: PropTypes.func,
|
|
196
|
+
onDropAccepted: PropTypes.func,
|
|
197
|
+
onDropRejected: PropTypes.func,
|
|
198
|
+
onDragEnter: PropTypes.func,
|
|
199
|
+
onDragOver: PropTypes.func,
|
|
200
|
+
onDragLeave: PropTypes.func,
|
|
201
|
+
shouldEnablePreview: PropTypes.bool,
|
|
202
|
+
shouldAllowMultiple: PropTypes.bool,
|
|
203
|
+
shouldAllowRepeats: PropTypes.bool,
|
|
204
|
+
maxSize: PropTypes.number,
|
|
205
|
+
minSize: PropTypes.number,
|
|
206
|
+
interaction: PropTypes.oneOf(['enabled', 'disabled', 'readonly']),
|
|
207
|
+
display: PropTypes.oneOf(['block', 'inline-block']),
|
|
208
|
+
height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
209
|
+
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
210
|
+
maxWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
211
|
+
minWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
197
212
|
margin: ThemeablePropTypes.spacing
|
|
198
213
|
}
|
|
199
214
|
|
|
@@ -22,13 +22,13 @@
|
|
|
22
22
|
* SOFTWARE.
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
function accepts(file:
|
|
25
|
+
function accepts(file: File, acceptProp: string | string[]) {
|
|
26
26
|
if (file && acceptProp && file.type !== 'application/x-moz-file') {
|
|
27
27
|
const acceptList = getAcceptList(acceptProp)
|
|
28
28
|
const mimeType = file.type || ''
|
|
29
29
|
const baseMimeType = mimeType.replace(/\/.*$/, '')
|
|
30
30
|
|
|
31
|
-
return acceptList.some((type
|
|
31
|
+
return acceptList.some((type) => {
|
|
32
32
|
if (type.charAt(0) === '.') {
|
|
33
33
|
// type is an extension like .pdf
|
|
34
34
|
if (!file.name) {
|
|
@@ -45,9 +45,9 @@ function accepts(file: any, acceptProp: any) {
|
|
|
45
45
|
return true
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
function getAcceptList(accept:
|
|
48
|
+
function getAcceptList(accept: string | string[]) {
|
|
49
49
|
const list = Array.isArray(accept) ? accept : accept.split(',')
|
|
50
|
-
return list.map((a
|
|
50
|
+
return list.map((a) => a.trim().replace(/^\w+$/, '.$&'))
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
export default accepts
|