@progress/kendo-react-upload
Version:
React Upload component helps users transfer files from their file systems to dedicated server handlers. KendoReact Upload package
480 lines (479 loc) • 15.1 kB
JavaScript
/**
* @license
*-------------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the package root for more information
*-------------------------------------------------------------------------------------------
*/
import * as m from "react";
import t from "prop-types";
import { validatePackage as R, getTabIndex as b, WatermarkOverlay as E } from "@progress/kendo-react-common";
import { UploadFileStatus as l } from "./interfaces/UploadFileStatus.mjs";
import { UploadNavigation as w } from "./UploadNavigation.mjs";
import S from "axios";
import C from "./utils/utils.mjs";
import p from "./utils/stateUtils.mjs";
import f from "./utils/connectionUtils.mjs";
import D from "./utils/validationUtils.mjs";
import { packageMetadata as O } from "./package-metadata.mjs";
const g = class g extends m.Component {
constructor(u) {
super(u), this._httpSubscriptions = {}, this._uploadNavigation = null, this.showLicenseWatermark = !1, this.focus = () => {
this._uploadNavigation && this._uploadNavigation.focus();
}, this.triggerUpload = () => {
this.onUpload();
}, this.uploadFiles = (i) => {
const e = this.async;
p.setFilesStatus(i, l.Uploading), p.groupForEach(i, (s, a) => {
const n = f.cloneRequestHeaders(e.saveHeaders || {}), r = {
target: this,
files: s,
headers: n,
additionalData: {}
};
this.props.onBeforeUpload && this.props.onBeforeUpload.call(void 0, r);
const c = f.populateRequestOptions(r.headers, this.async), v = f.populateUploadFormData(
s,
e.saveField,
r.additionalData
);
if (this.isCustomSave)
this.props.saveUrl(
s,
{ formData: v, requestOptions: c },
this.onUploadProgress
).then((d) => this.onUploadSuccess(d.uid)).catch((d) => this.onUploadError(d.uid));
else {
const d = S.CancelToken.source();
this._httpSubscriptions[a] = d, S({
method: e.saveMethod,
url: e.saveUrl,
data: v,
cancelToken: d.token,
...c,
onUploadProgress: (h) => this.onUploadProgress(a, h)
}).then((h) => this.onUploadSuccess(a, h)).catch((h) => this.onUploadError(a, h));
}
});
}, this.removeFiles = (i) => {
const e = this.async;
p.groupForEach(i, (s, a) => {
const n = f.cloneRequestHeaders(e.removeHeaders || {}), r = {
target: this,
files: s,
headers: n,
additionalData: {}
};
this.props.onBeforeRemove && this.props.onBeforeRemove.call(void 0, r);
const c = s.map((h) => h.name), v = f.populateRequestOptions(r.headers, this.async), d = f.populateRemoveFormData(
c,
e.removeField,
r.additionalData
);
this.isCustomRemove ? this.props.removeUrl(s, { formData: d, requestOptions: v }).then((h) => this.onRemoveSuccess(h.uid)).catch((h) => this.onRemoveError(h.uid)) : S({
method: e.removeMethod,
url: e.removeUrl,
data: d,
...v
}).then((h) => this.onRemoveSuccess(a, h)).catch((h) => this.onRemoveError(a, h));
});
}, this.onUpload = () => {
const i = this.fileStateCopy, e = p.groupFilesByUid(i), s = p.filesForUpload(e);
this.uploadFiles(s);
const a = () => {
if (this.props.onStatusChange) {
const n = {
target: this,
newState: i,
affectedFiles: p.flatFileGroup(s)
};
this.props.onStatusChange.call(void 0, n);
}
};
this.isControlled ? a() : this.setState({ files: i }, a);
}, this.onAdd = (i) => {
let e = C.getAllFileInfo(i), s;
if (e = C.assignGuidToFiles(e, this.async.batch), D.validateFiles(e, this.props.restrictions), this.props.multiple ? s = this.fileStateCopy : s = [], p.addMany(e, s), this.async.autoUpload) {
const n = p.groupFilesByUid(s);
this.uploadFiles(p.filesForUpload(n));
}
const a = () => {
if (this.props.onAdd) {
const n = {
target: this,
newState: s,
affectedFiles: e
};
this.props.onAdd.call(void 0, n);
}
};
this.isControlled ? a() : this.setState({ files: s }, a);
}, this.onUploadProgress = (i, e) => {
const s = Math.round(100 * e.loaded / (e.total || 0)) || 0, a = () => {
if (this.props.onProgress) {
const n = this.fileStateCopy, o = n.filter((c) => c.uid === i);
this.setFilesProgress(n, s);
const r = { target: this, newState: n, affectedFiles: o };
this.props.onProgress.call(void 0, r);
}
};
this.isControlled ? a() : this.setState((n) => {
const o = n.files, r = o.filter((c) => c.uid === i);
if (this.setFilesProgress(r, s), !!r.length)
return { files: o };
}, a);
}, this.onUploadSuccess = (i, e) => {
const s = this.fileStateCopy, a = s.filter((o) => o.uid === i);
a.forEach((o) => {
o.status = l.Uploaded, o.progress = 100;
}), delete this._httpSubscriptions[i];
const n = () => {
if (this.props.onStatusChange) {
const o = {
target: this,
newState: s,
affectedFiles: a,
response: e ? f.convertAxiosResponse(e) : void 0
};
this.props.onStatusChange.call(void 0, o);
}
};
this.isControlled ? n() : this.setState({ files: s }, n);
}, this.onUploadError = (i, e) => {
const s = this.fileStateCopy, a = s.filter((o) => o.uid === i);
if (a.forEach((o) => {
o.status = l.UploadFailed;
}), delete this._httpSubscriptions[i], !a.length)
return;
const n = () => {
if (this.props.onStatusChange) {
const o = {
target: this,
newState: s,
affectedFiles: a,
response: e ? f.convertAxiosResponse(e) : void 0
};
this.props.onStatusChange.call(void 0, o);
}
};
this.isControlled ? n() : this.setState({ files: s }, n);
}, this.onRemove = (i) => {
const e = this.fileStateCopy, s = e.filter((o) => o.uid === i), a = e.filter((o) => o.uid !== i);
if ([
l.Uploaded,
l.Initial,
l.RemoveFailed
].indexOf(s[0].status) > -1) {
const o = {
[i]: s
};
p.setFilesStatus(o, l.Removing), this.removeFiles(o);
const r = () => {
if (this.props.onStatusChange) {
const c = {
target: this,
newState: e,
affectedFiles: s
};
this.props.onStatusChange.call(void 0, c);
}
};
this.isControlled ? r() : this.setState({ files: e }, r);
} else {
const o = () => {
if (this.props.onRemove) {
const r = {
target: this,
newState: a,
affectedFiles: s
};
this.props.onRemove.call(void 0, r);
}
};
this.isControlled ? o() : this.setState({ files: a }, o);
}
}, this.onRemoveSuccess = (i, e) => {
const s = this.fileStateCopy, a = s.filter((r) => r.uid === i), n = s.filter((r) => r.uid !== i), o = () => {
if (this.props.onRemove) {
const r = {
target: this,
newState: n,
affectedFiles: a,
response: e ? f.convertAxiosResponse(e) : void 0
};
this.props.onRemove.call(void 0, r);
}
};
this.isControlled ? o() : this.setState({ files: n }, o);
}, this.onRemoveError = (i, e) => {
const s = this.fileStateCopy, a = s.filter((o) => o.uid === i);
a.forEach((o) => {
o.status = l.RemoveFailed;
});
const n = () => {
if (this.props.onStatusChange) {
const o = {
target: this,
newState: s,
affectedFiles: a,
response: e ? f.convertAxiosResponse(e) : void 0
};
this.props.onStatusChange.call(void 0, o);
}
};
this.isControlled ? n() : this.setState({ files: s }, n);
}, this.onRetry = (i) => {
const e = this.fileStateCopy, s = p.groupFilesByUid(e.filter((n) => n.uid === i));
p.setFilesStatus(s, l.Uploading), this.uploadFiles(s);
const a = () => {
if (this.props.onStatusChange) {
const n = {
target: this,
newState: e,
affectedFiles: p.flatFileGroup(s)
};
this.props.onStatusChange.call(void 0, n);
}
};
this.isControlled ? a() : this.setState({ files: e }, a);
}, this.onCancel = (i) => {
const e = this.fileStateCopy, s = e.filter((o) => o.uid !== i), a = e.filter((o) => o.uid === i);
if (this._httpSubscriptions[i] && (this._httpSubscriptions[i].cancel(), delete this._httpSubscriptions[i]), this.props.onCancel) {
const o = {
target: this,
uid: i
};
this.props.onCancel.call(void 0, o);
}
const n = () => {
if (this.props.onRemove) {
const o = {
target: this,
newState: s,
affectedFiles: a
};
this.props.onRemove.call(void 0, o);
}
};
this.isControlled ? n() : this.setState({ files: s }, n);
}, this.onClear = () => {
if (!this.files.length)
return;
Object.keys(this._httpSubscriptions).forEach((e) => {
this._httpSubscriptions[e].cancel();
}), this._httpSubscriptions = {};
const i = () => {
if (this.props.onRemove) {
const e = {
target: this,
newState: [],
affectedFiles: this.fileStateCopy
};
this.props.onRemove.call(void 0, e);
}
};
this.isControlled ? i() : this.setState({ files: [] }, i);
}, this.showLicenseWatermark = !R(O, { component: "Upload" }), this.state = {
files: u.defaultFiles || []
};
}
get async() {
const {
autoUpload: u,
batch: i,
removeField: e,
removeHeaders: s,
removeMethod: a,
removeUrl: n,
responseType: o,
saveField: r,
saveHeaders: c,
saveMethod: v,
saveUrl: d,
withCredentials: h
} = this.props;
return {
autoUpload: u,
batch: i,
removeField: e,
removeHeaders: s,
removeMethod: a,
removeUrl: n,
responseType: o,
saveField: r,
saveHeaders: c,
saveMethod: v,
saveUrl: d,
withCredentials: h
};
}
get files() {
return (this.isControlled ? this.props.files : this.state.files) || [];
}
get isControlled() {
return !this.props.defaultFiles;
}
get isCustomSave() {
return this.props.saveUrl && typeof this.props.saveUrl == "function";
}
get isCustomRemove() {
return this.props.removeUrl && typeof this.props.removeUrl == "function";
}
get fileStateCopy() {
return this.isControlled ? p.copyState(this.props.files) : p.copyState(this.state.files);
}
/**
* @hidden
*/
get actionElement() {
if (this._uploadNavigation)
return this._uploadNavigation.actionElement;
}
/**
* @hidden
*/
setFilesProgress(u, i) {
u.forEach((e) => {
e.progress = i, e.status === l.Uploading && i === 100 && (e.status = l.Uploaded);
});
}
/**
* @hidden
*/
render() {
var F;
const {
showFileList: u,
onAdd: i,
onRemove: e,
onCancel: s,
autoUpload: a,
showActionButtons: n,
actionsLayout: o,
tabIndex: r,
disabled: c,
...v
} = this.props, d = p.groupFilesByUid(this.files), h = p.filesForUpload(d);
return /* @__PURE__ */ m.createElement(m.Fragment, null, /* @__PURE__ */ m.createElement(
w,
{
groupedFiles: d,
className: this.props.className,
showFileList: u && !!Object.keys(d).length,
showActionButtons: n && !a && (!!Object.keys(h).length || !!((F = this.props.defaultFiles) != null && F.length)),
actionsLayout: o,
autoUpload: a,
disabled: c,
onAdd: this.onAdd,
onRemove: this.onRemove,
onClear: this.onClear,
onUpload: this.onUpload,
onRetry: this.onRetry,
onCancel: this.onCancel,
tabIndex: b(r, c),
ref: (y) => {
this._uploadNavigation = y;
},
...v
}
), this.showLicenseWatermark && /* @__PURE__ */ m.createElement(E, null));
}
};
g.defaultProps = {
autoUpload: !0,
batch: !1,
removeField: "fileNames",
removeHeaders: {},
removeMethod: "POST",
removeUrl: "",
responseType: "json",
saveField: "files",
saveHeaders: {},
saveMethod: "POST",
saveUrl: "",
withCredentials: !0,
restrictions: {
allowedExtensions: [],
maxFileSize: 0,
minFileSize: 0
},
multiple: !0,
showFileList: !0,
showActionButtons: !0,
actionsLayout: "end",
disabled: !1
}, g.propTypes = {
autoUpload: t.bool,
batch: t.bool,
withCredentials: t.bool,
saveField: t.string,
saveHeaders: t.object,
saveMethod: t.string,
saveUrl: t.oneOfType([t.string, t.func]),
responseType: t.oneOf(["arraybuffer", "blob", "json", "text"]),
removeField: t.string,
removeHeaders: t.object,
removeMethod: t.string,
removeUrl: t.oneOfType([t.string, t.func]),
multiple: t.bool,
disabled: t.bool,
showFileList: t.bool,
showActionButtons: t.bool,
actionsLayout: t.oneOf(["start", "center", "end", "stretched"]),
tabIndex: t.number,
accept: t.string,
listItemUI: t.oneOfType([
t.func,
t.string,
t.shape({ render: t.func.isRequired })
]),
restrictions: t.shape({
allowedExtensions: t.arrayOf(t.string),
maxFileSize: t.number,
minFileSize: t.number
}),
files: t.arrayOf(
t.shape({
uid: t.string,
name: t.string,
extension: t.string,
size: t.number,
validationErrors: t.arrayOf(t.string),
status: t.oneOf([
l.Initial,
l.RemoveFailed,
l.Removing,
l.Selected,
l.UploadFailed,
l.Uploaded,
l.Uploading
]),
progress: t.number,
getRawFile: t.func
})
),
defaultFiles: t.arrayOf(
t.shape({
uid: t.string,
name: t.string,
extension: t.string,
size: t.number,
validationErrors: t.arrayOf(t.string),
status: t.oneOf([
l.Initial,
l.RemoveFailed,
l.Removing,
l.Selected,
l.UploadFailed,
l.Uploaded,
l.Uploading
]),
progress: t.number,
getRawFile: t.func
})
)
};
let U = g;
export {
U as Upload
};