@6thquake/react-material
Version:
React components that implement Google's Material Design.
528 lines (473 loc) • 12.6 kB
JavaScript
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Button from '../Button';
import withStyles from '../styles/withStyles';
import Chip from '../Chip';
import Paper from '../Paper';
import CancelIcon from '@material-ui/icons/Cancel';
import { DragDropContext } from 'react-dnd';
import HTML5Backend, { NativeTypes } from 'react-dnd-html5-backend';
import TargetBox from './TargetBox';
import isString from 'lodash/isString';
const styles = theme => ({
button: {
margin: theme.spacing(1)
},
input: {
display: 'none'
},
paper: {
display: 'flex',
justifyContent: 'center',
flexWrap: 'wrap',
borderRadius: '5px'
},
chip: {
margin: theme.spacing(0.5)
},
wrap: {
width: '160px',
margin: '0 auto'
},
choose: {
display: 'inline-block'
},
array: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
},
inputImg: {
opacity: '0',
position: 'absolute',
display: 'block',
width: '140px',
height: '140px'
},
clickToUpload: {
width: '144px',
height: '110px',
margin: '4px',
border: '1px dashed #BDBDBD',
backgroundColor: '#e0e0e0',
textAlign: 'center',
borderRadius: '16px',
position: 'relative',
display: 'inline-block'
},
add: {
fontSize: '30px',
padding: '30px 0 0 0',
color: '#616161'
},
uploadText: {
fontSize: '15px',
color: '#000',
padding: '10px 0 0 0'
},
media: {
height: '130px',
width: '130px',
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%,-50%)',
overflow: 'hidden',
borderRadius: '5px',
backgroundSize: 'cover',
backgroundPosition: 'center'
},
chipDrag: {
height: '110px',
margin: theme.spacing(0.5),
padding: '0'
},
dragToUpload: {
minHeight: '300px',
minWidth: '400px',
border: '1px dashed #BDBDBD',
backgroundColor: '#F5F5F5',
textAlign: 'center',
borderRadius: '5px',
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'center',
alignItems: 'center'
},
mediaDrag: {
height: '100px',
width: '100px',
borderRadius: '10px',
backgroundSize: 'cover',
backgroundPosition: 'center'
},
icon: {
position: 'relative',
top: '-40px'
}
});
var _ref = React.createElement("div", null, "type is not correct");
class Upload extends Component {
constructor(props) {
super(props);
this.handleChangePath = e => {
for (let i = 0; i < e.target.files.length; i += 1) {
const file = e.target.files[i];
this.pathHandler(file);
}
};
this.handleDelete = (e, item) => {
const {
data,
files
} = this.state;
let indexToDelete = files.indexOf(item);
if (indexToDelete !== -1) {
files.splice(indexToDelete, 1);
}
indexToDelete = data.indexOf(item);
if (indexToDelete !== -1) {
data.splice(indexToDelete, 1);
}
this.setState({
files: files.slice(),
data: data.slice()
});
if (this.props.onDelete) {
this.props.onDelete(item); // delete item.preview;
}
/* type='drag',防止点击删除时弹出input框 */
if (e) {
e.preventDefault();
}
};
this.handleFileDrop = (item, monitor) => {
if (monitor) {
for (let i = 0; i < monitor.getItem().files.length; i++) {
const file = monitor.getItem().files[i];
this.pathHandler(file);
}
}
};
this.handleUpload = () => {
const {
data
} = this.state;
return this.props.upload(data);
};
this.state = {
data: [],
files: []
};
}
componentDidMount() {
const {
files
} = this.props;
if (files) {
for (let i = 0; i < files.length; i += 1) {
const file = files[i];
this.pathHandler(file);
}
}
}
componentDidUpdate(prevProps, prevState) {
const {
onChange
} = this.props;
if (prevState.data !== this.state.data) {
onChange(this.state.data);
}
}
/* 通过点击input标签添加图片 */
pathHandler(file) {
if (!file) {
return;
}
if (isString(file)) {
file = {
name: file,
url: file
};
}
const {
multiple
} = this.props;
if (this.state.files.indexOf(file) > -1) {
return;
}
if (!multiple) {
const {
files
} = this.state;
if (files.length > 0) {
for (let i = 0; i < files.length; i++) {
this.handleDelete(null, files[i]);
}
}
}
if (file instanceof File) {
this.setState(preState => ({
data: multiple ? [...preState.data, file] : [file]
}));
}
if (/^image\/\S+$/.test(file.type)) {
file.preview = React.createElement('img', {
src: URL.createObjectURL(file),
height: '100%',
width: '100%',
onLoad: e => {
URL.revokeObjectURL(e.target.src);
}
});
this.setState(preState => ({
files: multiple ? [...preState.files, file] : [file]
}));
} else {
if (!(file instanceof File)) {
const url = file.url || file.name;
if (/blob|http(s)?:\/\//.test(url)) {
file.preview = React.createElement('img', {
src: url,
height: '100%',
width: '100%'
});
}
}
this.setState(preState => ({
files: multiple ? [...preState.files, file] : [file]
}));
}
}
render() {
const {
classes,
type,
multiple,
disabled,
label
} = this.props;
const {
FILE
} = NativeTypes;
const {
files
} = this.state;
let manual;
let basic;
let img;
let drag;
const id = `RM-UPLOAD-${new Date().getTime()}`;
if (type === 'manual') {
manual = React.createElement("div", null, React.createElement("div", {
className: classes.wrap
}, React.createElement("input", {
accept: this.props.acceptType,
ref: input => this.selectInput = input,
className: classes.input,
id: id,
onChange: this.handleChangePath,
type: "file",
multiple: multiple,
disabled: disabled
}), React.createElement("label", {
htmlFor: id
}, this.props.children)), React.createElement(Paper, {
className: classes.paper
}, files.map(item => {
return React.createElement(Chip, {
key: item,
label: item.name,
onDelete: e => this.handleDelete(e, item),
className: classes.chip,
disabled: disabled
});
})), React.createElement("div", {
className: classes.wrap
}, React.createElement(Button, {
color: "primary",
variant: "contained",
className: classes.button,
onClick: this.handleUpload,
disabled: disabled
}, label)));
}
if (type === 'basic') {
basic = React.createElement("div", null, React.createElement("div", {
className: classes.choose
}, React.createElement("input", {
accept: this.props.acceptType,
ref: input => this.selectInput = input,
className: classes.input,
id: id,
onChange: this.handleChangePath,
type: "file",
multiple: multiple,
disabled: disabled
}), React.createElement("label", {
htmlFor: id
}, this.props.children)), React.createElement("div", {
className: classes.array
}, files.map(item => {
return React.createElement(Chip, {
key: item,
label: item.name,
onDelete: e => this.handleDelete(e, item),
className: classes.chip,
disabled: disabled
});
})));
}
if (type === 'img') {
img = React.createElement("div", null, React.createElement("input", {
accept: "image/*",
id: id,
ref: input => this.selectInput = input,
onChange: this.handleChangePath,
type: "file",
className: classes.inputImg,
multiple: multiple,
disabled: disabled
}), React.createElement("label", {
htmlFor: id
}, React.createElement("div", {
className: classes.array
}, files.map(item => {
const preview = React.createElement("div", {
className: classes.mediaDrag // style={{ backgroundImage: 'url(' + content + ')' }}
}, item.preview || item.name);
return React.createElement("div", {
className: classes.array
}, React.createElement(Chip, {
key: item,
label: preview,
onDelete: e => this.handleDelete(e, item),
className: classes.chipDrag,
deleteIcon: React.createElement(CancelIcon, {
className: classes.icon
}),
disabled: disabled
}));
}), (multiple || this.state.files.length <= 0) && React.createElement("div", {
className: classes.clickToUpload
}, React.createElement("div", {
className: classes.add
}, "+"), React.createElement("div", {
className: classes.uploadText
}, label), React.createElement("div", {
className: classes.media // style={{ backgroundImage: 'url(' + this.state.previewImg + ')' }}
})))));
}
if (type === 'drag') {
drag = React.createElement("div", null, React.createElement(TargetBox, {
accepts: [FILE],
onDrop: this.handleFileDrop,
beforeDragMention: this.props.beforeDragMention,
onDragMention: this.props.onDragMention
}, React.createElement("input", {
accept: this.props.acceptType,
ref: input => this.selectInput = input,
className: classes.input,
id: id,
onChange: this.handleChangePath,
type: "file",
multiple: multiple,
disabled: disabled
}), React.createElement("label", {
htmlFor: id
}, React.createElement("div", {
className: classes.dragToUpload
}, React.createElement("div", {
className: classes.array
}, files.map(item => {
/* 如果是图片就预览,否则显示文件名 */
const preview = React.createElement("div", {
className: classes.mediaDrag // style={{ backgroundImage: 'url(' + content + ')' }}
}, item.preview || item.name);
return React.createElement(Chip, {
key: item,
label: preview,
onDelete: e => this.handleDelete(e, item),
className: classes.chipDrag,
deleteIcon: React.createElement(CancelIcon, {
className: classes.icon
}),
disabled: disabled
});
}))))));
}
switch (type) {
case 'manual':
return manual;
case 'basic':
return basic;
case 'img':
return img;
case 'drag':
return drag;
default:
return _ref;
}
}
}
process.env.NODE_ENV !== "production" ? Upload.propTypes = {
/**
* 接受上传的文件类型
*/
acceptType: PropTypes.string,
/**
* 可选参数, 拖拽上传前的文字提示
*/
beforeDragMention: PropTypes.string,
/**
* 可选参数, 是否禁用
*/
disabled: PropTypes.bool,
/**
* 可选参数, 组件包含的所有文件
*/
files: PropTypes.array,
/**
* 按钮描述文字
*/
label: PropTypes.string,
/**
* 可选参数, 是否允许同时上传多个文件
*/
multiple: PropTypes.bool,
/**
* 上传文件集改变时触发的回调函数
*/
onChange: PropTypes.func,
/**
* 点击删除某个文件时触发的回调函数
*/
onDelete: PropTypes.func,
/**
* 可选参数, 拖拽文件至可拖拽区域上方时的文字提示
*/
onDragMention: PropTypes.string,
/**
* 上传方式, 'manual', 'basic', 'img', 'drag'可选
*/
type: PropTypes.oneOf(['manual', 'basic', 'img', 'drag']).isRequired,
/**
* 点击上传触发的函数
*/
upload: PropTypes.func
} : void 0;
Upload.defaultProps = {
acceptType: '*/*',
multiple: true,
disabled: false,
beforeDragMention: '',
onDragMention: '',
files: [],
onChange: files => {},
onDelete: file => {},
upload: files => {},
label: 'upload'
};
export default withStyles(styles, {
name: 'RMUpload'
})(DragDropContext(HTML5Backend)(Upload));