rsuite
Version:
A suite of react components
497 lines (431 loc) • 17 kB
JavaScript
"use strict";
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.default = void 0;
var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _react = _interopRequireWildcard(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _find = _interopRequireDefault(require("lodash/find"));
var _UploadFileItem = _interopRequireDefault(require("./UploadFileItem"));
var _UploadTrigger = _interopRequireDefault(require("./UploadTrigger"));
var _utils = require("../utils");
var _Plaintext = _interopRequireDefault(require("../Plaintext"));
var getFiles = function getFiles(event) {
if (typeof (event === null || event === void 0 ? void 0 : event['dataTransfer']) === 'object') {
var _event$dataTransfer;
return event === null || event === void 0 ? void 0 : (_event$dataTransfer = event['dataTransfer']) === null || _event$dataTransfer === void 0 ? void 0 : _event$dataTransfer.files;
}
if (event.target) {
return event.target['files'];
}
return [];
};
var createFile = function createFile(file) {
var fileKey = file.fileKey;
return (0, _extends2.default)({}, file, {
fileKey: fileKey || (0, _utils.guid)(),
progress: 0
});
};
function fileListReducer(files, action) {
var _action$files;
switch (action.type) {
// Add one or more files
case 'push':
return [].concat(files, action.files);
// Remove a file by `fileKey`
case 'remove':
return files.filter(function (f) {
return f.fileKey !== action.fileKey;
});
// Update a file
case 'updateFile':
return files.map(function (file) {
return file.fileKey === action.file.fileKey ? action.file : file;
});
// Initialization file list
case 'init':
return ((_action$files = action.files) === null || _action$files === void 0 ? void 0 : _action$files.map(function (file) {
// The state of the file needs to be preserved when the `fileList` is controlled.
return files.find(function (f) {
return f.fileKey === file.fileKey;
}) || createFile(file);
})) || [];
default:
throw new Error();
}
}
var useFileList = function useFileList(defaultFileList) {
if (defaultFileList === void 0) {
defaultFileList = [];
}
var fileListRef = (0, _react.useRef)(defaultFileList.map(createFile));
var fileListUpdateCallback = (0, _react.useRef)();
var _useReducer = (0, _react.useReducer)(fileListReducer, fileListRef.current),
fileList = _useReducer[0],
dispatch = _useReducer[1];
fileListRef.current = fileList;
(0, _react.useEffect)(function () {
var _fileListUpdateCallba;
(_fileListUpdateCallba = fileListUpdateCallback.current) === null || _fileListUpdateCallba === void 0 ? void 0 : _fileListUpdateCallba.call(fileListUpdateCallback, fileList);
fileListUpdateCallback.current = null;
}, [fileList]);
(0, _utils.useWillUnmount)(function () {
fileListUpdateCallback.current = null;
});
var dispatchCallback = (0, _react.useCallback)(function (action, callback) {
dispatch(action);
fileListUpdateCallback.current = callback;
}, []);
return [fileListRef, dispatchCallback];
};
var Uploader = /*#__PURE__*/_react.default.forwardRef(function (props, ref) {
var _props$as = props.as,
Component = _props$as === void 0 ? 'div' : _props$as,
_props$classPrefix = props.classPrefix,
classPrefix = _props$classPrefix === void 0 ? 'uploader' : _props$classPrefix,
className = props.className,
_props$listType = props.listType,
listType = _props$listType === void 0 ? 'text' : _props$listType,
defaultFileList = props.defaultFileList,
fileListProp = props.fileList,
_props$fileListVisibl = props.fileListVisible,
fileListVisible = _props$fileListVisibl === void 0 ? true : _props$fileListVisibl,
localeProp = props.locale,
style = props.style,
draggable = props.draggable,
_props$name = props.name,
name = _props$name === void 0 ? 'file' : _props$name,
_props$multiple = props.multiple,
multiple = _props$multiple === void 0 ? false : _props$multiple,
_props$disabled = props.disabled,
disabled = _props$disabled === void 0 ? false : _props$disabled,
readOnly = props.readOnly,
plaintext = props.plaintext,
accept = props.accept,
children = props.children,
toggleAs = props.toggleAs,
_props$removable = props.removable,
removable = _props$removable === void 0 ? true : _props$removable,
disabledFileItem = props.disabledFileItem,
maxPreviewFileSize = props.maxPreviewFileSize,
_props$method = props.method,
method = _props$method === void 0 ? 'POST' : _props$method,
_props$autoUpload = props.autoUpload,
autoUpload = _props$autoUpload === void 0 ? true : _props$autoUpload,
action = props.action,
headers = props.headers,
_props$withCredential = props.withCredentials,
withCredentials = _props$withCredential === void 0 ? false : _props$withCredential,
disableMultipart = props.disableMultipart,
_props$timeout = props.timeout,
timeout = _props$timeout === void 0 ? 0 : _props$timeout,
_props$data = props.data,
data = _props$data === void 0 ? {} : _props$data,
onRemove = props.onRemove,
onUpload = props.onUpload,
shouldUpload = props.shouldUpload,
shouldQueueUpdate = props.shouldQueueUpdate,
renderFileInfo = props.renderFileInfo,
renderThumbnail = props.renderThumbnail,
onPreview = props.onPreview,
onChange = props.onChange,
onSuccess = props.onSuccess,
onError = props.onError,
onProgress = props.onProgress,
onReupload = props.onReupload,
rest = (0, _objectWithoutPropertiesLoose2.default)(props, ["as", "classPrefix", "className", "listType", "defaultFileList", "fileList", "fileListVisible", "locale", "style", "draggable", "name", "multiple", "disabled", "readOnly", "plaintext", "accept", "children", "toggleAs", "removable", "disabledFileItem", "maxPreviewFileSize", "method", "autoUpload", "action", "headers", "withCredentials", "disableMultipart", "timeout", "data", "onRemove", "onUpload", "shouldUpload", "shouldQueueUpdate", "renderFileInfo", "renderThumbnail", "onPreview", "onChange", "onSuccess", "onError", "onProgress", "onReupload"]);
var _useClassNames = (0, _utils.useClassNames)(classPrefix),
merge = _useClassNames.merge,
withClassPrefix = _useClassNames.withClassPrefix,
prefix = _useClassNames.prefix;
var classes = merge(className, withClassPrefix(listType, {
draggable: draggable
}));
var _useCustom = (0, _utils.useCustom)('Uploader', localeProp),
locale = _useCustom.locale;
var rootRef = (0, _react.useRef)();
var xhrs = (0, _react.useRef)({});
var trigger = (0, _react.useRef)();
var _useFileList = useFileList(fileListProp || defaultFileList),
fileList = _useFileList[0],
dispatch = _useFileList[1];
(0, _react.useEffect)(function () {
if (typeof fileListProp !== 'undefined') {
// Force reset fileList in reducer, when `fileListProp` is updated
dispatch({
type: 'init',
files: fileListProp
});
}
}, [dispatch, fileListProp]);
var updateFileStatus = (0, _react.useCallback)(function (nextFile) {
dispatch({
type: 'updateFile',
file: nextFile
});
}, [dispatch]);
/**
* Clear the value in input.
*/
var cleanInputValue = (0, _react.useCallback)(function () {
var _trigger$current;
(_trigger$current = trigger.current) === null || _trigger$current === void 0 ? void 0 : _trigger$current.clearInput();
}, []);
/**
* Callback for successful file upload.
* @param file
* @param response
* @param event
* @param xhr
*/
var handleAjaxUploadSuccess = (0, _react.useCallback)(function (file, response, event, xhr) {
var nextFile = (0, _extends2.default)({}, file, {
status: 'finished',
progress: 100
});
updateFileStatus(nextFile);
onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess(response, nextFile, event, xhr);
}, [onSuccess, updateFileStatus]);
/**
* Callback for file upload error.
* @param file
* @param status
* @param event
* @param xhr
*/
var handleAjaxUploadError = (0, _react.useCallback)(function (file, status, event, xhr) {
var nextFile = (0, _extends2.default)({}, file, {
status: 'error'
});
updateFileStatus(nextFile);
onError === null || onError === void 0 ? void 0 : onError(status, nextFile, event, xhr);
}, [onError, updateFileStatus]);
/**
* Callback for file upload progress update.
* @param file
* @param percent
* @param event
* @param xhr
*/
var handleAjaxUploadProgress = (0, _react.useCallback)(function (file, percent, event, xhr) {
var nextFile = (0, _extends2.default)({}, file, {
status: 'uploading',
progress: percent
});
updateFileStatus(nextFile);
onProgress === null || onProgress === void 0 ? void 0 : onProgress(percent, nextFile, event, xhr);
}, [onProgress, updateFileStatus]);
/**
* Upload a single file.
* @param file
*/
var handleUploadFile = (0, _react.useCallback)(function (file) {
var _ajaxUpload = (0, _utils.ajaxUpload)({
name: name,
timeout: timeout,
headers: headers,
data: data,
method: method,
withCredentials: withCredentials,
disableMultipart: disableMultipart,
file: file.blobFile,
url: action,
onError: handleAjaxUploadError.bind(null, file),
onSuccess: handleAjaxUploadSuccess.bind(null, file),
onProgress: handleAjaxUploadProgress.bind(null, file)
}),
xhr = _ajaxUpload.xhr,
uploadData = _ajaxUpload.data;
updateFileStatus((0, _extends2.default)({}, file, {
status: 'uploading'
}));
if (file.fileKey) {
xhrs.current[file.fileKey] = xhr;
}
onUpload === null || onUpload === void 0 ? void 0 : onUpload(file, uploadData, xhr);
}, [name, timeout, headers, data, method, withCredentials, disableMultipart, action, handleAjaxUploadError, handleAjaxUploadSuccess, handleAjaxUploadProgress, updateFileStatus, onUpload]);
var handleAjaxUpload = (0, _react.useCallback)(function () {
fileList.current.forEach(function (file) {
var checkState = shouldUpload === null || shouldUpload === void 0 ? void 0 : shouldUpload(file);
if (checkState instanceof Promise) {
checkState.then(function (res) {
if (res) {
handleUploadFile(file);
}
});
return;
} else if (checkState === false) {
return;
}
if (file.status === 'inited') {
handleUploadFile(file);
}
});
cleanInputValue();
}, [cleanInputValue, fileList, handleUploadFile, shouldUpload]);
var handleUploadTriggerChange = function handleUploadTriggerChange(event) {
var files = getFiles(event);
var newFileList = [];
Array.from(files).forEach(function (file) {
newFileList.push({
blobFile: file,
name: file.name,
status: 'inited',
fileKey: (0, _utils.guid)()
});
});
var nextFileList = [].concat(fileList.current, newFileList);
var checkState = shouldQueueUpdate === null || shouldQueueUpdate === void 0 ? void 0 : shouldQueueUpdate(nextFileList, newFileList);
if (checkState === false) {
cleanInputValue();
return;
}
var upload = function upload() {
onChange === null || onChange === void 0 ? void 0 : onChange(nextFileList);
dispatch({
type: 'push',
files: newFileList
}, function () {
autoUpload && handleAjaxUpload();
});
};
if (checkState instanceof Promise) {
checkState.then(function (res) {
res && upload();
});
return;
}
upload();
};
var handleRemoveFile = function handleRemoveFile(fileKey) {
var _xhrs$current, _xhrs$current$file$fi;
var file = (0, _find.default)(fileList.current, function (f) {
return f.fileKey === fileKey;
});
var nextFileList = fileList.current.filter(function (f) {
return f.fileKey !== fileKey;
});
if (((_xhrs$current = xhrs.current) === null || _xhrs$current === void 0 ? void 0 : (_xhrs$current$file$fi = _xhrs$current[file.fileKey]) === null || _xhrs$current$file$fi === void 0 ? void 0 : _xhrs$current$file$fi.readyState) !== 4) {
var _xhrs$current$file$fi2;
(_xhrs$current$file$fi2 = xhrs.current[file.fileKey]) === null || _xhrs$current$file$fi2 === void 0 ? void 0 : _xhrs$current$file$fi2.abort();
}
dispatch({
type: 'remove',
fileKey: fileKey
});
onRemove === null || onRemove === void 0 ? void 0 : onRemove(file);
onChange === null || onChange === void 0 ? void 0 : onChange(nextFileList);
cleanInputValue();
};
var handleReupload = function handleReupload(file) {
autoUpload && handleUploadFile(file);
onReupload === null || onReupload === void 0 ? void 0 : onReupload(file);
}; // public API
var start = function start(file) {
if (file) {
handleUploadFile(file);
return;
}
handleAjaxUpload();
};
(0, _react.useImperativeHandle)(ref, function () {
return {
root: rootRef.current,
start: start
};
});
var renderList = [/*#__PURE__*/_react.default.createElement(_UploadTrigger.default, (0, _extends2.default)({}, rest, {
locale: locale,
name: name,
key: "trigger",
multiple: multiple,
draggable: draggable,
disabled: disabled,
readOnly: readOnly,
accept: accept,
ref: trigger,
onChange: handleUploadTriggerChange,
as: toggleAs
}), children)];
if (fileListVisible) {
renderList.push( /*#__PURE__*/_react.default.createElement("div", {
key: "items",
className: prefix('file-items')
}, fileList.current.map(function (file, index) {
return /*#__PURE__*/_react.default.createElement(_UploadFileItem.default, {
locale: locale,
key: file.fileKey || index,
file: file,
maxPreviewFileSize: maxPreviewFileSize,
listType: listType,
disabled: disabledFileItem,
onPreview: onPreview,
onReupload: handleReupload,
onCancel: handleRemoveFile,
renderFileInfo: renderFileInfo,
renderThumbnail: renderThumbnail,
removable: removable && !readOnly && !plaintext,
allowReupload: !readOnly && !plaintext
});
})));
}
if (plaintext) {
return /*#__PURE__*/_react.default.createElement(_Plaintext.default, {
localeKey: "notUploaded",
className: withClassPrefix(listType)
}, fileList.current.length ? renderList[1] : null);
}
if (listType === 'picture') {
renderList.reverse();
}
return /*#__PURE__*/_react.default.createElement(Component, {
ref: rootRef,
className: classes,
style: style
}, renderList);
});
Uploader.displayName = 'Uploader';
Uploader.propTypes = {
action: _propTypes.default.string.isRequired,
accept: _propTypes.default.string,
autoUpload: _propTypes.default.bool,
children: _propTypes.default.node,
className: _propTypes.default.string,
classPrefix: _propTypes.default.string,
defaultFileList: _propTypes.default.array,
fileList: _propTypes.default.array,
data: _propTypes.default.object,
multiple: _propTypes.default.bool,
disabled: _propTypes.default.bool,
disabledFileItem: _propTypes.default.bool,
name: _propTypes.default.string,
timeout: _propTypes.default.number,
withCredentials: _propTypes.default.bool,
headers: _propTypes.default.object,
locale: _propTypes.default.any,
listType: _propTypes.default.oneOf(['text', 'picture-text', 'picture']),
shouldQueueUpdate: _propTypes.default.func,
shouldUpload: _propTypes.default.func,
onChange: _propTypes.default.func,
onUpload: _propTypes.default.func,
onReupload: _propTypes.default.func,
onPreview: _propTypes.default.func,
onError: _propTypes.default.func,
onSuccess: _propTypes.default.func,
onProgress: _propTypes.default.func,
onRemove: _propTypes.default.func,
maxPreviewFileSize: _propTypes.default.number,
method: _propTypes.default.string,
style: _propTypes.default.object,
renderFileInfo: _propTypes.default.func,
renderThumbnail: _propTypes.default.func,
removable: _propTypes.default.bool,
fileListVisible: _propTypes.default.bool,
draggable: _propTypes.default.bool,
disableMultipart: _propTypes.default.bool
};
var _default = Uploader;
exports.default = _default;