react-file-reader-input
Version:
React file input component for complete control over styling and abstraction from file reading.
98 lines (85 loc) • 2.64 kB
JavaScript
// @flow
import * as React from 'react';
import ReactDOM from 'react-dom';
type Props = {
as?: 'binary' | 'buffer' | 'text' | 'url',
children?: React.Node,
onChange: Function,
style?: Object
};
export default class FileInput extends React.Component<Props> {
_reactFileReaderInput: any;
constructor(props: Props) {
// FileReader compatibility warning.
super(props);
const win = typeof window === 'object' ? window : {};
if (!win.File || !win.FileReader || !win.FileList || !win.Blob) {
console.warn(
'[react-file-reader-input] Some file APIs detected as not supported.' +
' File reader functionality may not fully work.'
);
}
}
handleChange = (e: any) => {
const files = Array.prototype.slice.call(e.target.files); // Convert into Array
const readAs = (this.props.as || 'url').toLowerCase();
// Build Promise List, each promise resolved by FileReader.onload.
Promise.all(files.map(file => new Promise((resolve, reject) => {
let reader = new FileReader();
reader.onload = result => {
// Resolve both the FileReader result and its original file.
resolve([result, file]);
};
// Read the file with format based on this.props.as.
switch (readAs) {
case 'binary': {
(reader: any).readAsBinaryString(file);
break;
}
case 'buffer': {
reader.readAsArrayBuffer(file);
break;
}
case 'text': {
reader.readAsText(file);
break;
}
case 'url': {
reader.readAsDataURL(file);
break;
}
}
})))
.then(zippedResults => {
// Run the callback after all files have been read.
this.props.onChange(e, zippedResults);
});
}
triggerInput = () => {
const input = ((ReactDOM.findDOMNode(this._reactFileReaderInput): any): HTMLInputElement);
if (input) {
input.click();
}
}
render() {
const { as, children, style, ...props } = this.props;
const hiddenInputStyle = children ? {
// If user passes in children, display children and hide input.
position: 'absolute',
top: '-9999px'
} : {};
return (
<div className="_react-file-reader-input" onClick={this.triggerInput} style={style}>
<input
{...props}
type="file"
ref={(c) => { this._reactFileReaderInput = c; }}
onChange={this.handleChange}
onClick={() => { this._reactFileReaderInput.value = null; }}
style={hiddenInputStyle}
/>
{children}
</div>
);
}
}