@livelybone/react-file-input
Version:
A file input component of React, support multiple inputs
468 lines (403 loc) • 16.6 kB
JavaScript
/**
* Bundle of @livelybone/react-file-input
* Generated: 2020-06-06
* Version: 1.2.4
* License: MIT
* Author: 2631541504@qq.com
*/
import simpleUniqueId from '@livelybone/simple-unique-id';
import { blobToBase64 } from 'base64-blob';
import React, { Component } from 'react';
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _typeof(obj) {
"@babel/helpers - typeof";
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function _typeof(obj) {
return typeof obj;
};
} else {
_typeof = function _typeof(obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
}
return _typeof(obj);
}
function _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return self;
}
function _possibleConstructorReturn(self, call) {
if (call && (_typeof(call) === "object" || typeof call === "function")) {
return call;
}
return _assertThisInitialized(self);
}
function _getPrototypeOf(o) {
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
return o.__proto__ || Object.getPrototypeOf(o);
};
return _getPrototypeOf(o);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function");
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
writable: true,
configurable: true
}
});
if (superClass) _setPrototypeOf(subClass, superClass);
}
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function isImg(file) {
var _ref = file,
name = _ref.name,
url = _ref.url;
var reg = /\.(jpe?g|png|webp|gif|svg)$/;
return name && reg.test(name) || url && reg.test(url);
}
function isFile(file) {
return file instanceof File || file instanceof Blob;
}
function convertFiles(files) {
return Promise.all(files.map(function (file) {
if (typeof file === 'string') {
var _name = file.split('?')[0].split(/\/+/).pop();
return {
name: _name,
url: file
};
}
var $file = 'file' in file && file.file || file;
var name = $file.name || file.name;
var url = 'url' in file ? file.url : '';
if (isFile($file)) {
return blobToBase64($file).then(function ($url) {
return {
name: name,
url: $url,
file: $file
};
});
}
return {
name: name,
url: url
};
}));
}
var Delete = function Delete(props) {
return React.createElement("svg", Object.assign({}, props, {
className: "react-file-delete",
viewBox: "0 0 1024 1024",
xmlns: "http://www.w3.org/2000/svg"
}), React.createElement("path", {
d: "M953.86906294 235.83183582l-57.99531457 0c2.76168122 8.28504494 2.76168122 19.33177108 2.76168122 27.61681603l0 635.18677903c0 60.75699579-49.71026963 110.46726541-110.46726541 110.46726542L235.83183582 1009.1026963c-60.75699579 0-110.46726541-49.71026963-110.46726541-110.46726542L125.36456912 263.44865185c0-8.28504494 2.76168122-19.33177108 2.76168122-27.61681603L70.13093706 235.83183582c-16.57008987 0-27.61681602-11.04672615-27.61681603-27.61681602s11.04672615-27.61681602 27.61681603-27.61681603l193.31771479 0L263.44865185 70.13093706c0-30.37849854 24.85513482-55.23363335 55.23363336-55.23363336l414.25224691 0c30.37849854 0 55.23363335 24.85513482 55.23363336 55.23363336l0 110.46726541 165.70089875 0c16.57008987 0 27.61681602 11.04672615 27.61681604 27.61681603S970.43915282 235.83183582 953.86906294 235.83183582zM732.93453212 70.13093706L318.68228521 70.13093706l0 110.46726541 414.25224691 0L732.93453212 70.13093706zM180.59820247 235.83183582l0 662.80359506c0 30.37849854 24.85513482 55.23363335 55.23363335 55.23363335l552.33632966 0c30.37849854 0 55.23363335-24.85513482 55.23363335-55.23363335L843.40179753 235.83183582 180.59820247 235.83183582zM705.31771479 788.16816418c-16.57008987 0-27.61681602-11.04672615-27.61681603-27.61681603L677.70089876 401.53273459c0-16.57008987 11.04672615-27.61681602 27.61681603-27.61681604s27.61681602 11.04672615 27.61681604 27.61681604l0 359.01861356C732.93453212 777.12143803 721.88780468 788.16816418 705.31771479 788.16816418zM512 815.7849815c-16.57008987 0-27.61681602-11.04672615-27.61681602-27.61681602L484.38318398 373.91591727c0-16.57008987 11.04672615-27.61681602 27.61681602-27.61681603s27.61681602 11.04672615 27.61681602 27.61681603l0 414.25224691C539.61681602 804.73825405 528.57008987 815.7849815 512 815.7849815zM318.68228521 788.16816418c-16.57008987 0-27.61681602-11.04672615-27.61681604-27.61681603L291.06546788 401.53273459c0-16.57008987 11.04672615-27.61681602 27.61681602-27.61681604 16.57008987 0 27.61681602 11.04672615 27.61681605 27.61681604l0 359.01861356C346.29910124 777.12143803 335.25237508 788.16816418 318.68228521 788.16816418z",
fill: "currentColor"
}));
};
var Add = function Add(props) {
return React.createElement("svg", Object.assign({}, props, {
className: "react-file-add",
viewBox: "0 0 1024 1024",
xmlns: "http://www.w3.org/2000/svg"
}), React.createElement("path", {
d: "M981.06100634 471.21208685H552.78791315V42.93899366a40.78791315 40.78791315 0 0 0-81.5758263 0v428.27309319H42.93899366a40.78791315 40.78791315 0 0 0 0 81.5758263h428.27309319v428.27309319a40.78791315 40.78791315 0 0 0 81.5758263 0V552.78791315h428.27309319a40.78791315 40.78791315 0 0 0 0-81.5758263z",
fill: "currentColor"
}));
};
var FileImg = function FileImg(props) {
return React.createElement("svg", Object.assign({}, props, {
className: "react-file-img",
viewBox: "0 0 1024 1024",
xmlns: "http://www.w3.org/2000/svg"
}), React.createElement("path", {
d: "M285.86666667 163.84m81.92 0l552.96 0q81.92 0 81.92 81.92l0 696.32q0 81.92-81.92 81.92l-552.96 0q-81.92 0-81.92-81.92l0-696.32q0-81.92 81.92-81.92Z",
fill: "currentColor",
opacity: "0.9"
}), React.createElement("path", {
d: "M490.66666667 399.36a30.72 30.72 0 0 1 30.72-30.72h348.16a30.72 30.72 0 1 1 0 61.44H521.38666667a30.72 30.72 0 0 1-30.72-30.72z m0 194.56a30.72 30.72 0 0 1 30.72-30.72h348.16a30.72 30.72 0 1 1 0 61.44H521.38666667a30.72 30.72 0 0 1-30.72-30.72z m30.72 163.84a30.72 30.72 0 1 0 0 61.44h348.16a30.72 30.72 0 1 0 0-61.44H521.38666667z",
fill: "#fff",
opacity: "0.3"
}), React.createElement("path", {
d: "M29.86666667 0m81.92 0l573.44 0q81.92 0 81.92 81.92l0 696.32q0 81.92-81.92 81.92l-573.44 0q-81.92 0-81.92-81.92l0-696.32q0-81.92 81.92-81.92Z",
fill: "currentColor"
}), React.createElement("path", {
d: "M193.70666667 266.24a30.72 30.72 0 0 1 30.72-30.72h348.16a30.72 30.72 0 1 1 0 61.44H224.42666667a30.72 30.72 0 0 1-30.72-30.72z m0 194.56a30.72 30.72 0 0 1 30.72-30.72h348.16a30.72 30.72 0 1 1 0 61.44H224.42666667a30.72 30.72 0 0 1-30.72-30.72z m30.72 163.84a30.72 30.72 0 1 0 0 61.44h348.16a30.72 30.72 0 1 0 0-61.44H224.42666667z",
fill: "#fff",
opacity: "0.4"
}));
};
var FileDisplay =
/*#__PURE__*/
function (_Component) {
_inherits(FileDisplay, _Component);
function FileDisplay() {
_classCallCheck(this, FileDisplay);
return _possibleConstructorReturn(this, _getPrototypeOf(FileDisplay).apply(this, arguments));
}
_createClass(FileDisplay, [{
key: "render",
value: function render() {
var _this$props = this.props,
file = _this$props.file,
uploading = _this$props.uploading,
readonly = _this$props.readonly,
uploadingContent = _this$props.uploadingContent,
beforeDelete = _this$props.beforeDelete,
onDelete = _this$props.onDelete,
onFileClick = _this$props.onFileClick;
var isImage = isImg(file);
return React.createElement("div", {
className: "react-file-display ".concat(isImage ? 'is-image' : ''),
title: file.name
}, isImage ? React.createElement("img", {
className: "react-file-img",
src: file.url,
alt: file.name,
onClick: onFileClick
}) : React.createElement(FileImg, {
onClick: onFileClick
}), React.createElement("span", {
className: "react-file-info-wrapper"
}, !readonly && React.createElement("span", {
className: "react-file-del-icon",
onClick: function onClick() {
Promise.resolve(beforeDelete()).then(function (should) {
return should && onDelete();
});
}
}, React.createElement(Delete, null)), file.name && React.createElement("span", {
className: "react-file-name"
}, file.name)), uploading && React.createElement("div", {
className: "uploading"
}, uploadingContent));
}
}]);
return FileDisplay;
}(Component);
var FileInput =
/*#__PURE__*/
function (_Component) {
_inherits(FileInput, _Component);
function FileInput() {
var _getPrototypeOf2;
var _this;
_classCallCheck(this, FileInput);
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(FileInput)).call.apply(_getPrototypeOf2, [this].concat(args)));
_defineProperty(_assertThisInitialized(_this), "state", {});
_defineProperty(_assertThisInitialized(_this), "inputEl", void 0);
_defineProperty(_assertThisInitialized(_this), "labelEl", void 0);
return _this;
}
_createClass(FileInput, [{
key: "render",
value: function render() {
var _this2 = this;
var _this$props = this.props,
id = _this$props.id,
accept = _this$props.accept,
tip = _this$props.tip,
readonly = _this$props.readonly,
_onChange = _this$props.onChange;
return React.createElement("label", {
className: "react-file-input".concat(tip ? ' has-tip' : ''),
htmlFor: id,
ref: function ref(el) {
return _this2.labelEl = el;
}
}, React.createElement(Add, null), tip && React.createElement("span", {
className: "react-file-input-tip"
}, tip), !readonly && React.createElement("input", {
type: "file",
hidden: true,
id: id,
ref: function ref(_ref) {
return _this2.inputEl = _ref;
},
accept: accept,
onChange: function onChange(ev) {
_onChange(ev.target.files && ev.target.files[0]);
ev.target.value = '';
}
}));
}
}]);
return FileInput;
}(Component);
var ReactFileInput =
/*#__PURE__*/
function (_Component) {
_inherits(ReactFileInput, _Component);
function ReactFileInput(props) {
var _this;
_classCallCheck(this, ReactFileInput);
_this = _possibleConstructorReturn(this, _getPrototypeOf(ReactFileInput).call(this, props));
_defineProperty(_assertThisInitialized(_this), "id", void 0);
_defineProperty(_assertThisInitialized(_this), "controlled", false);
_defineProperty(_assertThisInitialized(_this), "inputComp", void 0);
_this.state = {
files: []
};
_this.id = props.id || simpleUniqueId();
_this.controlled = 'files' in props;
if (_this.controlled) {
if (!('onChange' in props) || typeof props.onChange !== 'function') {
console.error('react-file-input: You provided a `files` prop to the component without an `onChange` handler. This will render a read-only field');
} else {
// eslint-disable-next-line no-console
console.log('react-file-input: The `files` prop is provided, it means the component is controlled, and you must provide `onChange` handler to handle the files change of the component');
}
}
if (props.files) {
convertFiles(props.files).then(function (files) {
_this.setState({
files: files
});
});
}
return _this;
}
_createClass(ReactFileInput, [{
key: "setFiles",
value: function setFiles(files) {
var _this2 = this;
var onChange = this.props.onChange;
if (this.controlled) {
onChange && onChange(files);
} else {
this.setState({
files: files
}, function () {
onChange && onChange(_this2.state.files);
});
}
}
}, {
key: "fileInput",
value: function fileInput(file) {
var _this3 = this;
if (file) {
(!this.controlled && isImg(file) ? blobToBase64(file) : Promise.resolve('')).then(function (url) {
var $file = {
file: file,
url: url,
name: file.name
};
if (!_this3.props.multiple) _this3.setFiles([$file]);else {
_this3.setFiles(_this3.state.files.concat($file));
}
});
}
}
}, {
key: "componentDidUpdate",
value: function componentDidUpdate(prevProps, prevState, snapshot) {
var _this4 = this;
if (this.props.files && prevProps.files !== this.props.files) {
convertFiles(this.props.files).then(function (files) {
_this4.setState({
files: files
});
});
}
}
}, {
key: "render",
value: function render() {
var _this5 = this;
var _this$props = this.props,
_beforeDelete = _this$props.beforeDelete,
_onFileClick = _this$props.onFileClick,
multiple = _this$props.multiple,
readonly = _this$props.readonly,
tip = _this$props.tip,
accept = _this$props.accept;
var files = multiple ? this.state.files : this.state.files.slice(0, 1);
var display = files.map(function (file, i) {
return React.createElement(FileDisplay, {
file: file,
key: i,
uploading: !!_this5.props.uploading && i === files.length - 1,
readonly: !!_this5.props.readonly,
uploadingContent: _this5.props.uploadingContent || 'uploading...',
onDelete: function onDelete() {
return _this5.setFiles(_this5.state.files.filter(function (f, index) {
return index !== i;
}));
},
beforeDelete: function beforeDelete() {
return _beforeDelete ? _beforeDelete(file) : true;
},
onFileClick: function onFileClick() {
if (_onFileClick) {
_onFileClick(file, i, _this5.state.files);
}
}
});
});
var input = React.createElement(FileInput, {
id: this.id,
ref: function ref(comp) {
return _this5.inputComp = comp;
},
tip: tip,
readonly: readonly,
accept: accept,
onChange: this.fileInput.bind(this)
});
return multiple ? React.createElement("div", {
className: "react-file-input-wrapper multiple".concat(readonly ? ' readonly' : '', " ").concat(this.props.className || '')
}, display, (!readonly || this.state.files.length < 1) && input) : React.createElement("div", {
className: "react-file-input-wrapper".concat(readonly ? ' readonly' : '', " ").concat(this.props.className || '')
}, display, this.state.files.length < 1 && input);
}
}]);
return ReactFileInput;
}(Component);
export default ReactFileInput;