-
Notifications
You must be signed in to change notification settings - Fork 48
/
index.tsx
119 lines (109 loc) · 3.08 KB
/
index.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import * as React from 'react'
import * as PropTypes from 'prop-types'
import * as PapaParse from 'papaparse'
export interface IFileInfo {
name: string
size: number
type: string
}
export interface CSVReaderProps {
accept?: string
cssClass?: string
cssInputClass?: string
cssLabelClass?: string
fileEncoding?: string
inputId?: string
inputName?: string
inputStyle?: object
label?: string | React.ReactNode
onError?: (error: Error) => void
onFileLoaded: (data: Array<any>, fileInfo: IFileInfo, originalFile?: File) => any
parserOptions?: PapaParse.ParseConfig
disabled?: boolean
strict?: boolean
}
const CSVReader = React.forwardRef<HTMLInputElement, CSVReaderProps>(
(
{
accept = '.csv, text/csv',
cssClass = 'csv-reader-input',
cssInputClass = 'csv-input',
cssLabelClass = 'csv-label',
fileEncoding = 'UTF-8',
inputId = 'react-csv-reader-input',
inputName = 'react-csv-reader-input',
inputStyle = {},
label,
onError = () => {},
onFileLoaded,
parserOptions = {} as PapaParse.ParseConfig,
disabled = false,
strict = false,
},
inputRef,
) => {
const handleChangeFile = (e: React.ChangeEvent<HTMLInputElement>) => {
let reader: FileReader = new FileReader()
const files: FileList = e.target.files!
if (files.length > 0) {
const fileInfo: IFileInfo = {
name: files[0].name,
size: files[0].size,
type: files[0].type,
}
if (strict && accept.indexOf(fileInfo.type) <= 0) {
onError(new Error(`[strict mode] Accept type not respected: got '${fileInfo.type}' but not in '${accept}'`))
return
}
reader.onload = (_event: Event) => {
const csvData = PapaParse.parse(
reader.result as string,
Object.assign(parserOptions, {
error: onError,
encoding: fileEncoding,
}),
)
onFileLoaded(csvData?.data ?? [], fileInfo, files[0])
}
reader.readAsText(files[0], fileEncoding)
}
}
return (
<div className={cssClass}>
{label && (
<label className={cssLabelClass} htmlFor={inputId}>
{label}
</label>
)}
<input
className={cssInputClass}
type="file"
id={inputId}
name={inputName}
style={inputStyle}
accept={accept}
onChange={handleChangeFile}
disabled={disabled}
ref={inputRef}
/>
</div>
)
},
)
CSVReader.propTypes = {
accept: PropTypes.string,
cssClass: PropTypes.string,
cssInputClass: PropTypes.string,
cssLabelClass: PropTypes.string,
fileEncoding: PropTypes.string,
inputId: PropTypes.string,
inputName: PropTypes.string,
inputStyle: PropTypes.object,
label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
onError: PropTypes.func,
onFileLoaded: PropTypes.func.isRequired,
parserOptions: PropTypes.object,
disabled: PropTypes.bool,
strict: PropTypes.bool,
}
export default CSVReader