sc-react-ions
Version:
An open source set of React components that implement Ambassador's Design and UX patterns.
160 lines (140 loc) • 4.04 kB
JavaScript
import React from 'react'
import PropTypes from 'prop-types'
import Dropzone from 'react-dropzone'
import Icon from '../Icon'
import classNames from 'classnames/bind'
import style from './style.scss'
/**
* The FileUpload component.
*/
class FileUpload extends React.Component {
constructor(props) {
super(props)
}
state = {
value: this.props.value,
files: []
}
static defaultProps = {
disabled: false,
value: '',
showPreview: false,
previewSize: 200
}
static propTypes = {
/**
* Whether the FileUpload is disabled.
*/
disabled: PropTypes.bool,
/**
* Text shown above the FileUpload.
*/
label: PropTypes.string,
/**
* Value of the FileUpload (can be path string or an array of file objects).
*/
value: PropTypes.oneOfType([
PropTypes.array,
PropTypes.string
]),
/**
* Name of the FileUpload.
*/
name: PropTypes.string,
/**
* Whether to show the preview under the FileUpload.
*/
showPreview: PropTypes.bool,
/**
* The preview size (maximum width and height).
*/
previewSize: PropTypes.number,
/**
* Optional styles to add to the FileUpload.
*/
optClass: PropTypes.string,
/**
* A callback function to be called when the FileUpload changes.
*/
changeCallback: PropTypes.func
}
_normalizeValue = value => {
if (!value || value === '') {
return []
} else if (typeof value === 'object') {
return value
}
const file = value.match(/.*\/(.*)$/)
return [{ preview: value, name: (file && file[1] ? file[1] : null) }]
}
componentWillMount = () => {
if (this.props.value && this.props.value !== '' && this.props.showPreview) {
this.setState({ files: this._normalizeValue(this.props.value) })
}
}
componentWillReceiveProps = nextProps => {
if (nextProps.value !== this.props.value) {
this.setState({ files: this._normalizeValue(nextProps.value) })
}
}
handleChange = () => {
if (typeof this.props.changeCallback === 'function') {
this.props.changeCallback({
target: {
name: this.props.name,
value: this.state.files
}
})
}
}
handleUpload = files => {
if (!this.props.disabled) {
this.setState({ files: files }, function () {
this.handleChange()
})
}
}
handleRemove = index => {
let savedFiles = this.state.files
savedFiles.splice(index, 1)
this.setState({ files: savedFiles }, function () {
this.handleChange()
})
}
getPreview = () => {
const imgStyle = {
maxWidth: this.props.previewSize + 'px',
maxHeight: this.props.previewSize + 'px'
}
return this.state.files.map((file, index) =>
<div key={index} className={style.image}>
<img style={imgStyle} src={file.preview} />
<Icon name='x' height='16' width='16' fill='#233040' onClick={this.handleRemove.bind(this, index)} />
</div>
)
}
render() {
const {
label,
value,
optClass,
showPreview,
previewSize,
changeCallback
} = this.props
const cx = classNames.bind(style)
const disabledClass = this.props.disabled ? style['disabled'] : ''
const fileUploadClass = cx(style['file-upload-component'], optClass, disabledClass)
return (
<div className={fileUploadClass}>
{ label ? <label>{label}</label> : null }
<Dropzone onDrop={this.handleUpload} className={style.dropzone} activeClassName={style.active} disableClick={this.props.disabled} multiple={false} disabled={this.props.disabled}>
<div>Drag and drop here to upload files or click to browse</div>
</Dropzone>
{ this.state.files[0] ? <div className={style.filename}><span>Filename:</span> {this.state.files[0].name}</div> : null }
{ showPreview ? <div className={style.preview}>{this.getPreview()}</div> : null }
</div>
)
}
}
export default FileUpload