@progress/kendo-react-upload
Version:
React Upload component helps users transfer files from their file systems to dedicated server handlers. KendoReact Upload package
471 lines (470 loc) • 14.9 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 e 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 d 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(v) {
super(v), this._httpSubscriptions = {}, this._uploadNavigation = null, this.showLicenseWatermark = !1, this.focus = () => {
this._uploadNavigation && this._uploadNavigation.focus();
}, this.triggerUpload = () => {
this.onUpload();
}, this.uploadFiles = (i) => {
const s = this.async;
d.setFilesStatus(i, l.Uploading), d.groupForEach(i, (t, a) => {
const n = f.cloneRequestHeaders(s.saveHeaders || {}), r = {
target: this,
files: t,
headers: n,
additionalData: {}
};
this.props.onBeforeUpload && this.props.onBeforeUpload.call(void 0, r);
const p = f.populateRequestOptions(r.headers, this.async), u = f.populateUploadFormData(
t,
s.saveField,
r.additionalData
);
if (this.isCustomSave)
this.props.saveUrl(
t,
{ formData: u, requestOptions: p },
this.onUploadProgress
).then((c) => this.onUploadSuccess(c.uid)).catch((c) => this.onUploadError(c.uid));
else {
const c = S.CancelToken.source();
this._httpSubscriptions[a] = c, S({
method: s.saveMethod,
url: s.saveUrl,
data: u,
cancelToken: c.token,
...p,
onUploadProgress: (h) => this.onUploadProgress(a, h)
}).then((h) => this.onUploadSuccess(a, h)).catch((h) => this.onUploadError(a, h));
}
});
}, this.removeFiles = (i) => {
const s = this.async;
d.groupForEach(i, (t, a) => {
const n = f.cloneRequestHeaders(s.removeHeaders || {}), r = {
target: this,
files: t,
headers: n,
additionalData: {}
};
this.props.onBeforeRemove && this.props.onBeforeRemove.call(void 0, r);
const p = t.map((h) => h.name), u = f.populateRequestOptions(r.headers, this.async), c = f.populateRemoveFormData(
p,
s.removeField,
r.additionalData
);
this.isCustomRemove ? this.props.removeUrl(t, { formData: c, requestOptions: u }).then((h) => this.onRemoveSuccess(h.uid)).catch((h) => this.onRemoveError(h.uid)) : S({
method: s.removeMethod,
url: s.removeUrl,
data: c,
...u
}).then((h) => this.onRemoveSuccess(a, h)).catch((h) => this.onRemoveError(a, h));
});
}, this.onUpload = () => {
const i = this.fileStateCopy, s = d.groupFilesByUid(i), t = d.filesForUpload(s);
this.uploadFiles(t);
const a = () => {
if (this.props.onStatusChange) {
const n = {
target: this,
newState: i,
affectedFiles: d.flatFileGroup(t)
};
this.props.onStatusChange.call(void 0, n);
}
};
this.isControlled ? a() : this.setState({ files: i }, a);
}, this.onAdd = (i) => {
let s = C.getAllFileInfo(i), t;
if (s = C.assignGuidToFiles(s, this.async.batch), D.validateFiles(s, this.props.restrictions), this.props.multiple ? t = this.fileStateCopy : t = [], d.addMany(s, t), this.async.autoUpload) {
const n = d.groupFilesByUid(t);
this.uploadFiles(d.filesForUpload(n));
}
const a = () => {
if (this.props.onAdd) {
const n = {
target: this,
newState: t,
affectedFiles: s
};
this.props.onAdd.call(void 0, n);
}
};
this.isControlled ? a() : this.setState({ files: t }, a);
}, this.onUploadProgress = (i, s) => {
let t = this.fileStateCopy, a = t.filter((o) => o.uid === i);
const n = () => {
if (this.props.onProgress) {
const o = { target: this, newState: t, affectedFiles: a };
this.props.onProgress.call(void 0, o);
}
};
this.setState((o) => {
const r = Math.round(100 * s.loaded / (s.total || 0)) || 0;
if (t = o.files, a = t.filter((p) => p.uid === i), !!a.length)
return a.forEach((p) => {
p.progress = r, p.status === l.Uploading && r === 100 && (p.status = l.Uploaded);
}), this.isControlled && n(), { files: t };
}, n);
}, this.onUploadSuccess = (i, s) => {
const t = this.fileStateCopy, a = t.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: t,
affectedFiles: a,
response: s ? f.convertAxiosResponse(s) : void 0
};
this.props.onStatusChange.call(void 0, o);
}
};
this.isControlled ? n() : this.setState({ files: t }, n);
}, this.onUploadError = (i, s) => {
const t = this.fileStateCopy, a = t.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: t,
affectedFiles: a,
response: s ? f.convertAxiosResponse(s) : void 0
};
this.props.onStatusChange.call(void 0, o);
}
};
this.isControlled ? n() : this.setState({ files: t }, n);
}, this.onRemove = (i) => {
const s = this.fileStateCopy, t = s.filter((o) => o.uid === i), a = s.filter((o) => o.uid !== i);
if ([
l.Uploaded,
l.Initial,
l.RemoveFailed
].indexOf(t[0].status) > -1) {
const o = {
[i]: t
};
d.setFilesStatus(o, l.Removing), this.removeFiles(o);
const r = () => {
if (this.props.onStatusChange) {
const p = {
target: this,
newState: s,
affectedFiles: t
};
this.props.onStatusChange.call(void 0, p);
}
};
this.isControlled ? r() : this.setState({ files: s }, r);
} else {
const o = () => {
if (this.props.onRemove) {
const r = {
target: this,
newState: a,
affectedFiles: t
};
this.props.onRemove.call(void 0, r);
}
};
this.isControlled ? o() : this.setState({ files: a }, o);
}
}, this.onRemoveSuccess = (i, s) => {
const t = this.fileStateCopy, a = t.filter((r) => r.uid === i), n = t.filter((r) => r.uid !== i), o = () => {
if (this.props.onRemove) {
const r = {
target: this,
newState: n,
affectedFiles: a,
response: s ? f.convertAxiosResponse(s) : void 0
};
this.props.onRemove.call(void 0, r);
}
};
this.isControlled ? o() : this.setState({ files: n }, o);
}, this.onRemoveError = (i, s) => {
const t = this.fileStateCopy, a = t.filter((o) => o.uid === i);
a.forEach((o) => {
o.status = l.RemoveFailed;
});
const n = () => {
if (this.props.onStatusChange) {
const o = {
target: this,
newState: t,
affectedFiles: a,
response: s ? f.convertAxiosResponse(s) : void 0
};
this.props.onStatusChange.call(void 0, o);
}
};
this.isControlled ? n() : this.setState({ files: t }, n);
}, this.onRetry = (i) => {
const s = this.fileStateCopy, t = d.groupFilesByUid(s.filter((n) => n.uid === i));
d.setFilesStatus(t, l.Uploading), this.uploadFiles(t);
const a = () => {
if (this.props.onStatusChange) {
const n = {
target: this,
newState: s,
affectedFiles: d.flatFileGroup(t)
};
this.props.onStatusChange.call(void 0, n);
}
};
this.isControlled ? a() : this.setState({ files: s }, a);
}, this.onCancel = (i) => {
const s = this.fileStateCopy, t = s.filter((o) => o.uid !== i), a = s.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: t,
affectedFiles: a
};
this.props.onRemove.call(void 0, o);
}
};
this.isControlled ? n() : this.setState({ files: t }, n);
}, this.onClear = () => {
if (!this.files.length)
return;
Object.keys(this._httpSubscriptions).forEach((s) => {
this._httpSubscriptions[s].cancel();
}), this._httpSubscriptions = {};
const i = () => {
if (this.props.onRemove) {
const s = {
target: this,
newState: [],
affectedFiles: this.fileStateCopy
};
this.props.onRemove.call(void 0, s);
}
};
this.isControlled ? i() : this.setState({ files: [] }, i);
}, this.showLicenseWatermark = !R(O, { component: "Upload" }), this.state = {
files: v.defaultFiles || []
};
}
get async() {
const {
autoUpload: v,
batch: i,
removeField: s,
removeHeaders: t,
removeMethod: a,
removeUrl: n,
responseType: o,
saveField: r,
saveHeaders: p,
saveMethod: u,
saveUrl: c,
withCredentials: h
} = this.props;
return {
autoUpload: v,
batch: i,
removeField: s,
removeHeaders: t,
removeMethod: a,
removeUrl: n,
responseType: o,
saveField: r,
saveHeaders: p,
saveMethod: u,
saveUrl: c,
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 ? d.copyState(this.props.files) : d.copyState(this.state.files);
}
/**
* @hidden
*/
get actionElement() {
if (this._uploadNavigation)
return this._uploadNavigation.actionElement;
}
/**
* @hidden
*/
render() {
var F;
const {
showFileList: v,
onAdd: i,
onRemove: s,
onCancel: t,
autoUpload: a,
showActionButtons: n,
actionsLayout: o,
tabIndex: r,
disabled: p,
...u
} = this.props, c = d.groupFilesByUid(this.files), h = d.filesForUpload(c);
return /* @__PURE__ */ m.createElement(m.Fragment, null, /* @__PURE__ */ m.createElement(
w,
{
groupedFiles: c,
className: this.props.className,
showFileList: v && !!Object.keys(c).length,
showActionButtons: n && !a && (!!Object.keys(h).length || !!((F = this.props.defaultFiles) != null && F.length)),
actionsLayout: o,
autoUpload: a,
disabled: p,
onAdd: this.onAdd,
onRemove: this.onRemove,
onClear: this.onClear,
onUpload: this.onUpload,
onRetry: this.onRetry,
onCancel: this.onCancel,
tabIndex: b(r, p),
ref: (y) => this._uploadNavigation = y,
...u
}
), 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: e.bool,
batch: e.bool,
withCredentials: e.bool,
saveField: e.string,
saveHeaders: e.object,
saveMethod: e.string,
saveUrl: e.oneOfType([e.string, e.func]),
responseType: e.oneOf(["arraybuffer", "blob", "json", "text"]),
removeField: e.string,
removeHeaders: e.object,
removeMethod: e.string,
removeUrl: e.oneOfType([e.string, e.func]),
multiple: e.bool,
disabled: e.bool,
showFileList: e.bool,
showActionButtons: e.bool,
actionsLayout: e.oneOf(["start", "center", "end", "stretched"]),
tabIndex: e.number,
accept: e.string,
listItemUI: e.oneOfType([
e.func,
e.string,
e.shape({ render: e.func.isRequired })
]),
restrictions: e.shape({
allowedExtensions: e.arrayOf(e.string),
maxFileSize: e.number,
minFileSize: e.number
}),
files: e.arrayOf(
e.shape({
uid: e.string,
name: e.string,
extension: e.string,
size: e.number,
validationErrors: e.arrayOf(e.string),
status: e.oneOf([
l.Initial,
l.RemoveFailed,
l.Removing,
l.Selected,
l.UploadFailed,
l.Uploaded,
l.Uploading
]),
progress: e.number,
getRawFile: e.func
})
),
defaultFiles: e.arrayOf(
e.shape({
uid: e.string,
name: e.string,
extension: e.string,
size: e.number,
validationErrors: e.arrayOf(e.string),
status: e.oneOf([
l.Initial,
l.RemoveFailed,
l.Removing,
l.Selected,
l.UploadFailed,
l.Uploaded,
l.Uploading
]),
progress: e.number,
getRawFile: e.func
})
)
};
let U = g;
export {
U as Upload
};