UNPKG

@livelybone/react-file-input

Version:

A file input component of React, support multiple inputs

468 lines (403 loc) 16.6 kB
/** * 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;