@sia.soul/sia-react-ui 0.1.28 → 0.1.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-NEYUBLLB.js → chunk-KT7DIBXX.js} +389 -95
- package/dist/{core-CTe-Sfl1.d.cts → core-B687rqFa.d.cts} +141 -81
- package/dist/{core-DlvCqFU7.d.ts → core-BwuvPHYM.d.ts} +141 -81
- package/dist/core.cjs +376 -73
- package/dist/core.css +261 -12
- package/dist/core.d.cts +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/core.js +1 -1
- package/dist/index.cjs +388 -98
- package/dist/index.css +261 -12
- package/dist/index.d.cts +15 -10
- package/dist/index.d.ts +15 -10
- package/dist/index.js +22 -26
- package/package.json +1 -1
|
@@ -141,6 +141,7 @@ function Card({
|
|
|
141
141
|
// src/components/Tag.tsx
|
|
142
142
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
143
143
|
function Tag({
|
|
144
|
+
color,
|
|
144
145
|
status = "default",
|
|
145
146
|
compact = false,
|
|
146
147
|
variant = "soft",
|
|
@@ -151,13 +152,16 @@ function Tag({
|
|
|
151
152
|
onClose,
|
|
152
153
|
className = "",
|
|
153
154
|
children,
|
|
155
|
+
style,
|
|
154
156
|
...props
|
|
155
157
|
}) {
|
|
158
|
+
const customColor = color?.trim() ? variant === "outlined" ? { borderColor: color, color, backgroundColor: "transparent" } : variant === "filled" ? { backgroundColor: color, color: "#fff", borderColor: "transparent" } : { color, backgroundColor: `color-mix(in srgb, ${color} 10%, transparent)`, borderColor: `color-mix(in srgb, ${color} 35%, transparent)` } : void 0;
|
|
156
159
|
return /* @__PURE__ */ jsxs3(
|
|
157
160
|
"span",
|
|
158
161
|
{
|
|
159
162
|
className: `sia-tag${closable && closeOnHover ? " sia-tag--close-on-hover" : ""} sia-tag--${status} sia-tag--${variant}${compact ? " sia-tag--compact" : ""}${disabled ? " sia-tag--disabled" : ""} ${className}`.trim(),
|
|
160
163
|
"aria-disabled": disabled || void 0,
|
|
164
|
+
style: customColor ? { ...customColor, ...style } : style,
|
|
161
165
|
...withTitleTooltip(props),
|
|
162
166
|
children: [
|
|
163
167
|
icon ? /* @__PURE__ */ jsx3("span", { className: "sia-tag__icon", children: icon }) : null,
|
|
@@ -910,137 +914,427 @@ function Image({ fallback, placeholder, preview = true, rootClassName = "", clas
|
|
|
910
914
|
}
|
|
911
915
|
|
|
912
916
|
// src/components/Upload.tsx
|
|
913
|
-
import {
|
|
914
|
-
|
|
917
|
+
import { forwardRef, useEffect as useEffect3, useImperativeHandle, useRef as useRef5, useState as useState6 } from "react";
|
|
918
|
+
|
|
919
|
+
// src/components/uploadFiles.ts
|
|
920
|
+
function acceptsUploadFile(file, accept) {
|
|
921
|
+
if (!accept?.trim()) return true;
|
|
922
|
+
return accept.split(",").some((part) => {
|
|
923
|
+
const rule = part.trim().toLowerCase();
|
|
924
|
+
const type = file.type.toLowerCase();
|
|
925
|
+
return rule.startsWith(".") ? file.name.toLowerCase().endsWith(rule) : rule.endsWith("/*") ? type.startsWith(rule.slice(0, -1)) : type === rule;
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
function includeUploadPath(path, recursive) {
|
|
929
|
+
return recursive || path.split("/").filter(Boolean).length <= 2;
|
|
930
|
+
}
|
|
931
|
+
async function readUploadEntries(entries, recursive) {
|
|
932
|
+
const files = [];
|
|
933
|
+
async function visit(entry, path, depth) {
|
|
934
|
+
if (entry.isFile) {
|
|
935
|
+
const file = await new Promise((resolve, reject) => entry.file(resolve, reject));
|
|
936
|
+
files.push({ file, path });
|
|
937
|
+
} else if (entry.isDirectory && (recursive || depth === 0)) {
|
|
938
|
+
const reader = entry.createReader();
|
|
939
|
+
while (true) {
|
|
940
|
+
const batch = await new Promise((resolve, reject) => reader.readEntries(resolve, reject));
|
|
941
|
+
if (!batch.length) break;
|
|
942
|
+
for (const child of batch) await visit(child, `${path}/${child.name}`, depth + 1);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
for (const entry of entries) await visit(entry, entry.name, 0);
|
|
947
|
+
return files;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
// src/components/uploadRequest.ts
|
|
951
|
+
function sendUploadRequest(config, options) {
|
|
952
|
+
const xhr = new XMLHttpRequest();
|
|
953
|
+
const abort = () => xhr.abort();
|
|
954
|
+
const cleanup = () => options.signal.removeEventListener("abort", abort);
|
|
955
|
+
xhr.open(config.method ?? "POST", config.action, true);
|
|
956
|
+
xhr.withCredentials = config.withCredentials ?? false;
|
|
957
|
+
xhr.timeout = config.timeout ?? 0;
|
|
958
|
+
for (const [name, value] of Object.entries(config.headers ?? {})) xhr.setRequestHeader(name, value);
|
|
959
|
+
xhr.upload.onprogress = (event) => {
|
|
960
|
+
if (event.lengthComputable) options.onProgress(event.loaded / event.total * 100);
|
|
961
|
+
};
|
|
962
|
+
xhr.onload = () => {
|
|
963
|
+
cleanup();
|
|
964
|
+
if (xhr.status < 200 || xhr.status >= 300) {
|
|
965
|
+
options.onError(new Error(`\u4E0A\u4F20\u5931\u8D25\uFF1AHTTP ${xhr.status}`));
|
|
966
|
+
return;
|
|
967
|
+
}
|
|
968
|
+
let response = xhr.responseText;
|
|
969
|
+
try {
|
|
970
|
+
response = JSON.parse(xhr.responseText);
|
|
971
|
+
} catch {
|
|
972
|
+
}
|
|
973
|
+
options.onSuccess(response, config.url);
|
|
974
|
+
};
|
|
975
|
+
xhr.onerror = () => {
|
|
976
|
+
cleanup();
|
|
977
|
+
options.onError(new Error("\u4E0A\u4F20\u7F51\u7EDC\u9519\u8BEF\uFF0C\u8BF7\u68C0\u67E5\u8FDE\u63A5\u4E0E\u8DE8\u57DF\u914D\u7F6E"));
|
|
978
|
+
};
|
|
979
|
+
xhr.ontimeout = () => {
|
|
980
|
+
cleanup();
|
|
981
|
+
options.onError(new Error("\u4E0A\u4F20\u8D85\u65F6"));
|
|
982
|
+
};
|
|
983
|
+
xhr.onabort = cleanup;
|
|
984
|
+
options.signal.addEventListener("abort", abort, { once: true });
|
|
985
|
+
if (options.signal.aborted) {
|
|
986
|
+
cleanup();
|
|
987
|
+
return { abort };
|
|
988
|
+
}
|
|
989
|
+
try {
|
|
990
|
+
if (config.body === "file") xhr.send(options.file);
|
|
991
|
+
else {
|
|
992
|
+
const body = new FormData();
|
|
993
|
+
for (const [name, value] of Object.entries(config.data ?? {})) body.append(name, value);
|
|
994
|
+
body.append(config.name ?? "file", options.file, options.filename);
|
|
995
|
+
xhr.send(body);
|
|
996
|
+
}
|
|
997
|
+
} catch (error) {
|
|
998
|
+
cleanup();
|
|
999
|
+
throw error;
|
|
1000
|
+
}
|
|
1001
|
+
return { abort };
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
// src/components/Upload.tsx
|
|
1005
|
+
import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
915
1006
|
var LIST_IGNORE = /* @__PURE__ */ Symbol("SIA_UPLOAD_LIST_IGNORE");
|
|
916
|
-
function
|
|
1007
|
+
function useThumbnail(file) {
|
|
1008
|
+
const [local, setLocal] = useState6();
|
|
1009
|
+
useEffect3(() => {
|
|
1010
|
+
if (!file?.thumbUrl && file?.originFileObj?.type.startsWith("image/")) {
|
|
1011
|
+
const url = URL.createObjectURL(file.originFileObj);
|
|
1012
|
+
setLocal(url);
|
|
1013
|
+
return () => URL.revokeObjectURL(url);
|
|
1014
|
+
}
|
|
1015
|
+
setLocal(void 0);
|
|
1016
|
+
}, [file?.originFileObj, file?.thumbUrl]);
|
|
1017
|
+
return file?.thumbUrl || local || (file?.type?.startsWith("image/") || /\.(png|jpe?g|gif|webp|avif|svg)(\?|$)/i.test(file?.url ?? "") ? file?.url : void 0);
|
|
1018
|
+
}
|
|
1019
|
+
function UploadItem({ file, files, props, actions }) {
|
|
1020
|
+
const source = useThumbnail(file);
|
|
1021
|
+
const [failed, setFailed] = useState6(false);
|
|
1022
|
+
useEffect3(() => setFailed(false), [source]);
|
|
1023
|
+
const node = /* @__PURE__ */ jsxs7("div", { className: `sia-upload__item sia-upload__item--${file.status ?? "ready"}`, children: [
|
|
1024
|
+
props.listType !== "text" ? /* @__PURE__ */ jsx7(Button, { variant: "text", className: "sia-upload__thumbnail", "aria-label": `\u9884\u89C8 ${file.name}`, onClick: actions.preview, disabled: !source && !props.onPreview, children: source && !failed ? /* @__PURE__ */ jsx7("img", { src: source, alt: file.name, onError: () => setFailed(true) }) : /* @__PURE__ */ jsx7(Icon, { name: file.type?.startsWith("image/") ? "image" : "file", size: 28 }) }) : /* @__PURE__ */ jsx7(Icon, { name: file.status === "done" ? "circle-check" : "file", size: 16 }),
|
|
1025
|
+
/* @__PURE__ */ jsx7("span", { className: "sia-upload__name", ...withTitleTooltip({ title: file.relativePath || file.name }), children: file.url ? /* @__PURE__ */ jsx7("a", { href: file.url, target: "_blank", rel: "noreferrer", children: file.name }) : file.name }),
|
|
1026
|
+
/* @__PURE__ */ jsx7(Button, { variant: "text", className: "sia-upload__remove", disabled: props.disabled, "aria-label": `\u79FB\u9664 ${file.name}`, onClick: () => void actions.remove(), children: /* @__PURE__ */ jsx7(Icon, { name: "close", size: 14 }) }),
|
|
1027
|
+
file.status === "uploading" && /* @__PURE__ */ jsxs7("div", { className: "sia-upload__uploading", children: [
|
|
1028
|
+
/* @__PURE__ */ jsxs7("span", { children: [
|
|
1029
|
+
"\u4E0A\u4F20\u4E2D ",
|
|
1030
|
+
Math.round(file.percent ?? 0),
|
|
1031
|
+
"%"
|
|
1032
|
+
] }),
|
|
1033
|
+
/* @__PURE__ */ jsx7("span", { className: "sia-upload__progress", role: "progressbar", "aria-label": `${file.name} \u4E0A\u4F20\u8FDB\u5EA6`, "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": file.percent ?? 0, children: /* @__PURE__ */ jsx7("span", { style: { width: `${file.percent ?? 0}%` } }) })
|
|
1034
|
+
] }),
|
|
1035
|
+
file.status === "error" && /* @__PURE__ */ jsx7("span", { className: "sia-upload__error", children: "\u4E0A\u4F20\u5931\u8D25" })
|
|
1036
|
+
] });
|
|
1037
|
+
return /* @__PURE__ */ jsx7(Fragment4, { children: props.itemRender ? props.itemRender(node, file, files, actions) : node });
|
|
1038
|
+
}
|
|
1039
|
+
var UploadRoot = forwardRef(function UploadRoot2({
|
|
917
1040
|
accept,
|
|
918
1041
|
multiple = false,
|
|
919
1042
|
directory = false,
|
|
1043
|
+
recursive = true,
|
|
1044
|
+
pastable = false,
|
|
920
1045
|
disabled = false,
|
|
1046
|
+
autoUpload = true,
|
|
921
1047
|
maxCount: maxCount2,
|
|
922
1048
|
fileList,
|
|
923
1049
|
defaultFileList = [],
|
|
924
1050
|
listType = "text",
|
|
925
1051
|
showUploadList = true,
|
|
926
1052
|
beforeUpload,
|
|
1053
|
+
request,
|
|
927
1054
|
customRequest,
|
|
928
1055
|
onChange,
|
|
929
1056
|
onRemove,
|
|
1057
|
+
onReject,
|
|
1058
|
+
onReadError,
|
|
1059
|
+
onPreview,
|
|
1060
|
+
itemRender,
|
|
930
1061
|
children,
|
|
931
1062
|
className = "",
|
|
932
1063
|
onDragOver,
|
|
1064
|
+
onDragLeave,
|
|
933
1065
|
onDrop,
|
|
1066
|
+
onPaste,
|
|
1067
|
+
tabIndex,
|
|
934
1068
|
...props
|
|
935
|
-
}) {
|
|
1069
|
+
}, ref) {
|
|
936
1070
|
const inputRef = useRef5(null);
|
|
937
|
-
const
|
|
938
|
-
const
|
|
939
|
-
const
|
|
1071
|
+
const [internalFiles, setInternalFiles] = useState6(defaultFileList);
|
|
1072
|
+
const files = fileList ?? internalFiles;
|
|
1073
|
+
const filesRef = useRef5(files);
|
|
940
1074
|
filesRef.current = files;
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
1075
|
+
const tasks = useRef5(/* @__PURE__ */ new Map());
|
|
1076
|
+
const mounted = useRef5(true);
|
|
1077
|
+
const [dragging, setDragging] = useState6(false);
|
|
1078
|
+
const [preview, setPreview] = useState6();
|
|
1079
|
+
const previewSource = useThumbnail(preview);
|
|
1080
|
+
const limit = maxCount2 === void 0 || !Number.isFinite(maxCount2) ? Infinity : Math.max(0, Math.floor(maxCount2));
|
|
1081
|
+
const full = files.length >= limit;
|
|
1082
|
+
const current = useRef5({ disabled, directory, recursive });
|
|
1083
|
+
current.current = { disabled, directory, recursive };
|
|
1084
|
+
function cancel(uid) {
|
|
1085
|
+
const task = tasks.current.get(uid);
|
|
1086
|
+
tasks.current.delete(uid);
|
|
1087
|
+
task?.controller.abort();
|
|
1088
|
+
try {
|
|
1089
|
+
task?.handle?.abort?.();
|
|
1090
|
+
} catch {
|
|
953
1091
|
}
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
1092
|
+
task?.finish();
|
|
1093
|
+
}
|
|
1094
|
+
useEffect3(() => {
|
|
1095
|
+
mounted.current = true;
|
|
1096
|
+
return () => {
|
|
1097
|
+
mounted.current = false;
|
|
1098
|
+
[...tasks.current.keys()].forEach(cancel);
|
|
1099
|
+
};
|
|
1100
|
+
}, []);
|
|
1101
|
+
useEffect3(() => {
|
|
1102
|
+
for (const uid of tasks.current.keys()) if (!files.some((file) => file.uid === uid)) cancel(uid);
|
|
1103
|
+
if (preview && !files.some((file) => file.uid === preview.uid)) setPreview(void 0);
|
|
1104
|
+
}, [files, preview]);
|
|
1105
|
+
function emit(file, next, event) {
|
|
1106
|
+
if (!mounted.current) return;
|
|
1107
|
+
filesRef.current = next;
|
|
1108
|
+
if (fileList === void 0) setInternalFiles(next);
|
|
1109
|
+
onChange?.({ file, fileList: next, event });
|
|
1110
|
+
}
|
|
1111
|
+
function start(file) {
|
|
1112
|
+
if (current.current.disabled || !mounted.current || file.status === "done" || !file.originFileObj) return Promise.resolve();
|
|
1113
|
+
const existing = tasks.current.get(file.uid);
|
|
1114
|
+
if (existing) return existing.done;
|
|
1115
|
+
let finish = () => {
|
|
1116
|
+
};
|
|
1117
|
+
const done = new Promise((resolve) => {
|
|
1118
|
+
finish = resolve;
|
|
1119
|
+
});
|
|
1120
|
+
const task = { controller: new AbortController(), done, finish };
|
|
1121
|
+
tasks.current.set(file.uid, task);
|
|
1122
|
+
const active = () => mounted.current && tasks.current.get(file.uid) === task && !task.controller.signal.aborted && filesRef.current.some((entry) => entry.uid === file.uid);
|
|
1123
|
+
const update = (patch, event) => {
|
|
1124
|
+
if (!active()) return;
|
|
1125
|
+
const next = { ...filesRef.current.find((entry) => entry.uid === file.uid), ...patch };
|
|
1126
|
+
emit(next, filesRef.current.map((entry) => entry.uid === file.uid ? next : entry), event);
|
|
1127
|
+
};
|
|
1128
|
+
const settle = () => {
|
|
1129
|
+
if (tasks.current.get(file.uid) === task) tasks.current.delete(file.uid);
|
|
1130
|
+
finish();
|
|
1131
|
+
};
|
|
1132
|
+
const options = {
|
|
1133
|
+
file: file.originFileObj,
|
|
1134
|
+
filename: file.name,
|
|
1135
|
+
uploadFile: file,
|
|
1136
|
+
relativePath: file.relativePath || file.name,
|
|
1137
|
+
signal: task.controller.signal,
|
|
961
1138
|
onProgress: (percent) => {
|
|
962
|
-
|
|
963
|
-
const progressList = filesRef.current.map((entry) => entry.uid === item.uid ? progressing : entry);
|
|
964
|
-
emit(progressing, progressList);
|
|
1139
|
+
if (Number.isFinite(percent)) update({ percent: Math.max(0, Math.min(100, percent)) }, "progress");
|
|
965
1140
|
},
|
|
966
|
-
onSuccess: (response) => {
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1141
|
+
onSuccess: (response, url) => {
|
|
1142
|
+
if (!active()) return;
|
|
1143
|
+
update({ status: "done", percent: 100, response, ...url ? { url } : {} }, "success");
|
|
1144
|
+
settle();
|
|
970
1145
|
},
|
|
971
1146
|
onError: (error) => {
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1147
|
+
if (!active()) return;
|
|
1148
|
+
update({ status: "error", error }, "error");
|
|
1149
|
+
settle();
|
|
975
1150
|
}
|
|
976
1151
|
};
|
|
977
|
-
|
|
978
|
-
|
|
1152
|
+
update({ status: "uploading", percent: 0, error: void 0 }, "start");
|
|
1153
|
+
void (async () => {
|
|
1154
|
+
try {
|
|
1155
|
+
if (!active()) return;
|
|
1156
|
+
const result = await beforeUpload?.(options.file, filesRef.current.flatMap((entry) => entry.originFileObj ? [entry.originFileObj] : []));
|
|
1157
|
+
if (!active()) return;
|
|
1158
|
+
if (result === LIST_IGNORE) {
|
|
1159
|
+
settle();
|
|
1160
|
+
emit(file, filesRef.current.filter((entry) => entry.uid !== file.uid), "remove");
|
|
1161
|
+
return;
|
|
1162
|
+
}
|
|
1163
|
+
if (result === false || !customRequest && !request) {
|
|
1164
|
+
update({ status: "ready" }, "cancel");
|
|
1165
|
+
settle();
|
|
1166
|
+
return;
|
|
1167
|
+
}
|
|
1168
|
+
if (result instanceof File) {
|
|
1169
|
+
options.file = result;
|
|
1170
|
+
options.filename = result.name;
|
|
1171
|
+
}
|
|
1172
|
+
if (customRequest) task.handle = await customRequest(options) || void 0;
|
|
1173
|
+
else {
|
|
1174
|
+
const config = typeof request === "function" ? await request({ ...file, originFileObj: options.file, name: options.filename }, task.controller.signal) : request;
|
|
1175
|
+
if (active()) task.handle = sendUploadRequest(config, options);
|
|
1176
|
+
}
|
|
1177
|
+
if (task.controller.signal.aborted) task.handle?.abort?.();
|
|
1178
|
+
} catch (error) {
|
|
1179
|
+
options.onError(error);
|
|
1180
|
+
}
|
|
1181
|
+
})();
|
|
1182
|
+
return done;
|
|
979
1183
|
}
|
|
980
|
-
function
|
|
981
|
-
const
|
|
982
|
-
|
|
983
|
-
|
|
1184
|
+
function abort(uid) {
|
|
1185
|
+
const ids = uid ? [uid] : [...tasks.current.keys()];
|
|
1186
|
+
for (const id of ids) {
|
|
1187
|
+
if (!tasks.current.has(id)) continue;
|
|
1188
|
+
cancel(id);
|
|
1189
|
+
const file = filesRef.current.find((entry) => entry.uid === id);
|
|
1190
|
+
if (file) {
|
|
1191
|
+
const next = { ...file, status: "ready", percent: 0 };
|
|
1192
|
+
emit(next, filesRef.current.map((entry) => entry.uid === id ? next : entry), "cancel");
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
async function remove(uid) {
|
|
1197
|
+
if (current.current.disabled) return;
|
|
1198
|
+
const file = filesRef.current.find((entry) => entry.uid === uid);
|
|
1199
|
+
if (!file) return;
|
|
1200
|
+
try {
|
|
1201
|
+
if (await onRemove?.(file) === false || !mounted.current || current.current.disabled) return;
|
|
1202
|
+
cancel(uid);
|
|
1203
|
+
emit(file, filesRef.current.filter((entry) => entry.uid !== uid), "remove");
|
|
1204
|
+
} catch {
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
useImperativeHandle(ref, () => ({
|
|
1208
|
+
upload: async (uid) => {
|
|
1209
|
+
await Promise.all(filesRef.current.filter((file) => (!uid || file.uid === uid) && file.status !== "done").map(start));
|
|
1210
|
+
},
|
|
1211
|
+
abort,
|
|
1212
|
+
remove
|
|
1213
|
+
}));
|
|
1214
|
+
function ingest(entries) {
|
|
1215
|
+
if (current.current.disabled || !mounted.current) return;
|
|
1216
|
+
const filtered = directory ? entries.filter((entry) => includeUploadPath(entry.path, recursive)) : entries;
|
|
1217
|
+
const selected = multiple || directory ? filtered : filtered.slice(0, 1);
|
|
1218
|
+
const added = [];
|
|
1219
|
+
for (const { file, path } of selected) {
|
|
1220
|
+
if (!acceptsUploadFile(file, accept)) {
|
|
1221
|
+
onReject?.({ file, reason: "accept" });
|
|
1222
|
+
continue;
|
|
1223
|
+
}
|
|
1224
|
+
if (filesRef.current.length >= limit) {
|
|
1225
|
+
onReject?.({ file, reason: "max-count" });
|
|
1226
|
+
continue;
|
|
1227
|
+
}
|
|
1228
|
+
const item = { uid: `upload-${Date.now()}-${Math.random().toString(36).slice(2)}`, name: file.name, size: file.size, type: file.type, relativePath: path, originFileObj: file, status: "ready", percent: 0 };
|
|
1229
|
+
emit(item, [...filesRef.current, item], "add");
|
|
1230
|
+
added.push(item);
|
|
1231
|
+
}
|
|
1232
|
+
if (autoUpload) added.forEach((file) => {
|
|
1233
|
+
void start(file);
|
|
1234
|
+
});
|
|
984
1235
|
}
|
|
985
|
-
function handleDrop(event) {
|
|
1236
|
+
async function handleDrop(event) {
|
|
986
1237
|
onDrop?.(event);
|
|
987
|
-
|
|
1238
|
+
setDragging(false);
|
|
1239
|
+
if (event.defaultPrevented) return;
|
|
988
1240
|
event.preventDefault();
|
|
989
|
-
|
|
990
|
-
|
|
1241
|
+
if (disabled) return;
|
|
1242
|
+
const fallback = [...event.dataTransfer.files].map((file) => ({ file, path: file.webkitRelativePath || file.name }));
|
|
1243
|
+
const entries = [...event.dataTransfer.items].map((item) => item.webkitGetAsEntry?.()).filter((entry) => !!entry);
|
|
1244
|
+
try {
|
|
1245
|
+
if (entries.length) ingest(await readUploadEntries(entries.filter((entry) => directory || !entry.isDirectory), recursive));
|
|
1246
|
+
else ingest(fallback);
|
|
1247
|
+
} catch (error) {
|
|
1248
|
+
if (mounted.current) onReadError?.(error);
|
|
1249
|
+
}
|
|
991
1250
|
}
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
1251
|
+
function handlePaste(event) {
|
|
1252
|
+
onPaste?.(event);
|
|
1253
|
+
if (event.defaultPrevented || disabled || !pastable) return;
|
|
1254
|
+
const selected = [...event.clipboardData.files];
|
|
1255
|
+
if (!selected.length) return;
|
|
1256
|
+
event.preventDefault();
|
|
1257
|
+
ingest(selected.map((file) => ({ file, path: file.name })));
|
|
996
1258
|
}
|
|
1259
|
+
const trigger = !(listType === "picture-card" && full) && /* @__PURE__ */ jsx7("div", { className: "sia-upload__trigger", children: /* @__PURE__ */ jsx7(Button, { className: "sia-upload__choose", disabled: disabled || full, onClick: () => inputRef.current?.click(), children: children ?? (listType === "picture-card" ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
1260
|
+
/* @__PURE__ */ jsx7(Icon, { name: "plus", size: 24 }),
|
|
1261
|
+
/* @__PURE__ */ jsx7("span", { children: "\u4E0A\u4F20\u56FE\u7247" })
|
|
1262
|
+
] }) : /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
1263
|
+
/* @__PURE__ */ jsx7(Icon, { name: "upload", size: 16 }),
|
|
1264
|
+
directory ? "\u9009\u62E9\u6587\u4EF6\u5939" : "\u9009\u62E9\u6587\u4EF6"
|
|
1265
|
+
] })) }) });
|
|
997
1266
|
return /* @__PURE__ */ jsxs7(
|
|
998
1267
|
"div",
|
|
999
1268
|
{
|
|
1000
|
-
|
|
1269
|
+
...withTitleTooltip(props),
|
|
1270
|
+
className: `sia-upload sia-upload--${listType}${dragging ? " is-dragging" : ""}${disabled ? " is-disabled" : ""} ${className}`.trim(),
|
|
1271
|
+
tabIndex: tabIndex ?? (pastable && !disabled ? 0 : void 0),
|
|
1272
|
+
onPaste: handlePaste,
|
|
1001
1273
|
onDragOver: (event) => {
|
|
1002
1274
|
onDragOver?.(event);
|
|
1003
|
-
if (!event.defaultPrevented
|
|
1275
|
+
if (!event.defaultPrevented) {
|
|
1276
|
+
event.preventDefault();
|
|
1277
|
+
if (!disabled) setDragging(true);
|
|
1278
|
+
}
|
|
1004
1279
|
},
|
|
1005
|
-
|
|
1006
|
-
|
|
1280
|
+
onDragLeave: (event) => {
|
|
1281
|
+
onDragLeave?.(event);
|
|
1282
|
+
if (!event.currentTarget.contains(event.relatedTarget)) setDragging(false);
|
|
1283
|
+
},
|
|
1284
|
+
onDrop: (event) => void handleDrop(event),
|
|
1007
1285
|
children: [
|
|
1008
1286
|
/* @__PURE__ */ jsx7(
|
|
1009
1287
|
"input",
|
|
1010
1288
|
{
|
|
1011
1289
|
ref: inputRef,
|
|
1012
|
-
id,
|
|
1013
1290
|
className: "sia-upload__input",
|
|
1014
1291
|
type: "file",
|
|
1015
1292
|
accept,
|
|
1016
|
-
multiple,
|
|
1017
|
-
disabled,
|
|
1018
|
-
...
|
|
1019
|
-
onChange:
|
|
1293
|
+
multiple: multiple || directory,
|
|
1294
|
+
disabled: disabled || full,
|
|
1295
|
+
...directory ? { webkitdirectory: "", directory: "" } : {},
|
|
1296
|
+
onChange: (event) => {
|
|
1297
|
+
ingest([...event.currentTarget.files ?? []].map((file) => ({ file, path: file.webkitRelativePath || file.name })));
|
|
1298
|
+
event.currentTarget.value = "";
|
|
1299
|
+
}
|
|
1020
1300
|
}
|
|
1021
1301
|
),
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
/* @__PURE__ */ jsx7(
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1302
|
+
listType !== "picture-card" && trigger,
|
|
1303
|
+
/* @__PURE__ */ jsxs7("div", { className: "sia-upload__list", children: [
|
|
1304
|
+
showUploadList && files.map((file) => /* @__PURE__ */ jsx7(UploadItem, { file, files, props: { listType, disabled, itemRender, onPreview }, actions: {
|
|
1305
|
+
upload: () => start(file),
|
|
1306
|
+
abort: () => abort(file.uid),
|
|
1307
|
+
remove: () => remove(file.uid),
|
|
1308
|
+
preview: () => {
|
|
1309
|
+
if (onPreview) onPreview(file);
|
|
1310
|
+
else setPreview(file);
|
|
1311
|
+
}
|
|
1312
|
+
} }, file.uid)),
|
|
1313
|
+
listType === "picture-card" && trigger
|
|
1314
|
+
] }),
|
|
1315
|
+
/* @__PURE__ */ jsx7(ImagePreview, { open: !!preview && !!(preview.url || previewSource), src: preview?.url || previewSource, alt: preview?.name, onOpenChange: (open) => {
|
|
1316
|
+
if (!open) setPreview(void 0);
|
|
1317
|
+
} })
|
|
1029
1318
|
]
|
|
1030
1319
|
}
|
|
1031
1320
|
);
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
|
-
return /* @__PURE__ */ jsx7(UploadRoot, { ...props, className: `sia-upload-dragger ${className}`.trim(), children: children ?? /* @__PURE__ */ jsxs7("
|
|
1035
|
-
/* @__PURE__ */ jsx7(Icon, { name: "upload", size:
|
|
1036
|
-
/* @__PURE__ */
|
|
1037
|
-
|
|
1321
|
+
});
|
|
1322
|
+
var UploadDragger = forwardRef(function UploadDragger2({ hint = "\u652F\u6301\u5355\u4E2A\u6216\u6279\u91CF\u4E0A\u4F20", children, className = "", ...props }, ref) {
|
|
1323
|
+
return /* @__PURE__ */ jsx7(UploadRoot, { ...props, ref, className: `sia-upload-dragger ${className}`.trim(), children: children ?? /* @__PURE__ */ jsxs7("span", { className: "sia-upload-dragger__content", children: [
|
|
1324
|
+
/* @__PURE__ */ jsx7(Icon, { name: "upload", size: 32 }),
|
|
1325
|
+
/* @__PURE__ */ jsxs7("strong", { children: [
|
|
1326
|
+
"\u70B9\u51FB\u6216\u62D6\u62FD",
|
|
1327
|
+
props.directory ? "\u6587\u4EF6\u5939" : "\u6587\u4EF6",
|
|
1328
|
+
"\u5230\u6B64\u533A\u57DF\u4E0A\u4F20"
|
|
1329
|
+
] }),
|
|
1330
|
+
/* @__PURE__ */ jsx7("span", { children: hint }),
|
|
1331
|
+
props.pastable && /* @__PURE__ */ jsx7("span", { children: "\u805A\u7126\u6B64\u533A\u57DF\u540E\u6309 Ctrl / \u2318 + V \u7C98\u8D34\u6587\u4EF6\u6216\u622A\u56FE" })
|
|
1038
1332
|
] }) });
|
|
1039
|
-
}
|
|
1333
|
+
});
|
|
1040
1334
|
var Upload = Object.assign(UploadRoot, {
|
|
1041
|
-
/**
|
|
1335
|
+
/** 可点击、键盘操作和拖拽的上传区域,ref 支持手动上传、取消及移除。 */
|
|
1042
1336
|
Dragger: UploadDragger,
|
|
1043
|
-
/** beforeUpload
|
|
1337
|
+
/** beforeUpload 返回时移除该文件,不进行上传。 */
|
|
1044
1338
|
LIST_IGNORE
|
|
1045
1339
|
});
|
|
1046
1340
|
|
|
@@ -1150,11 +1444,11 @@ var message = {
|
|
|
1150
1444
|
};
|
|
1151
1445
|
|
|
1152
1446
|
// src/components/Breadcrumb.tsx
|
|
1153
|
-
import { Fragment as
|
|
1447
|
+
import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1154
1448
|
function Breadcrumb({ items, separator = "/", itemRender, className = "", ...props }) {
|
|
1155
1449
|
return /* @__PURE__ */ jsx9("nav", { "aria-label": "\u9762\u5305\u5C51\u5BFC\u822A", ...withTitleTooltip(props), className: `sia-breadcrumb ${className}`.trim(), children: /* @__PURE__ */ jsx9("ol", { className: "sia-breadcrumb__list", children: items.map((item, index) => {
|
|
1156
1450
|
const current = index === items.length - 1;
|
|
1157
|
-
const content = /* @__PURE__ */ jsxs9(
|
|
1451
|
+
const content = /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
1158
1452
|
item.icon ? /* @__PURE__ */ jsx9("span", { className: "sia-breadcrumb__icon", "aria-hidden": "true", children: item.icon }) : null,
|
|
1159
1453
|
/* @__PURE__ */ jsx9("span", { className: "sia-breadcrumb__title", children: item.title })
|
|
1160
1454
|
] });
|
|
@@ -1171,8 +1465,8 @@ function Breadcrumb({ items, separator = "/", itemRender, className = "", ...pro
|
|
|
1171
1465
|
}
|
|
1172
1466
|
|
|
1173
1467
|
// src/components/Typography.tsx
|
|
1174
|
-
import { useEffect as
|
|
1175
|
-
import { Fragment as
|
|
1468
|
+
import { useEffect as useEffect4, useLayoutEffect as useLayoutEffect3, useRef as useRef6, useState as useState7 } from "react";
|
|
1469
|
+
import { Fragment as Fragment6, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1176
1470
|
function TypographyContent({
|
|
1177
1471
|
as: Tag2 = "span",
|
|
1178
1472
|
type,
|
|
@@ -1194,22 +1488,22 @@ function TypographyContent({
|
|
|
1194
1488
|
const contentRef = useRef6(null);
|
|
1195
1489
|
const editRef = useRef6(null);
|
|
1196
1490
|
const timer = useRef6();
|
|
1197
|
-
const [localText, setLocalText] =
|
|
1198
|
-
const [draft, setDraft] =
|
|
1199
|
-
const [editing, setEditing] =
|
|
1200
|
-
const [copied, setCopied] =
|
|
1201
|
-
const [copyError, setCopyError] =
|
|
1202
|
-
const [expanded, setExpanded] =
|
|
1203
|
-
const [overflow, setOverflow] =
|
|
1491
|
+
const [localText, setLocalText] = useState7();
|
|
1492
|
+
const [draft, setDraft] = useState7("");
|
|
1493
|
+
const [editing, setEditing] = useState7(false);
|
|
1494
|
+
const [copied, setCopied] = useState7(false);
|
|
1495
|
+
const [copyError, setCopyError] = useState7(false);
|
|
1496
|
+
const [expanded, setExpanded] = useState7(false);
|
|
1497
|
+
const [overflow, setOverflow] = useState7(false);
|
|
1204
1498
|
const editConfig = typeof editable === "object" ? editable : void 0;
|
|
1205
1499
|
const content = editConfig?.text ?? localText ?? children;
|
|
1206
1500
|
const requestedRows = typeof ellipsis === "object" ? ellipsis.rows ?? 1 : 1;
|
|
1207
1501
|
const rows = Number.isFinite(requestedRows) ? Math.max(1, Math.floor(requestedRows)) : 1;
|
|
1208
1502
|
const expandable = typeof ellipsis === "object" && ellipsis.expandable;
|
|
1209
|
-
|
|
1503
|
+
useEffect4(() => {
|
|
1210
1504
|
setLocalText(void 0);
|
|
1211
1505
|
}, [children]);
|
|
1212
|
-
|
|
1506
|
+
useEffect4(() => () => clearTimeout(timer.current), []);
|
|
1213
1507
|
useLayoutEffect3(() => {
|
|
1214
1508
|
const element = contentRef.current;
|
|
1215
1509
|
if (!element || !ellipsis || editing || expanded) return;
|
|
@@ -1275,7 +1569,7 @@ function TypographyContent({
|
|
|
1275
1569
|
/* @__PURE__ */ jsx10(Button, { size: "small", onClick: () => finish(false), children: "\u53D6\u6D88" }),
|
|
1276
1570
|
/* @__PURE__ */ jsx10(Button, { size: "small", variant: "primary", onClick: () => finish(true), children: "\u4FDD\u5B58" })
|
|
1277
1571
|
] })
|
|
1278
|
-
] }) : /* @__PURE__ */ jsxs10(
|
|
1572
|
+
] }) : /* @__PURE__ */ jsxs10(Fragment6, { children: [
|
|
1279
1573
|
/* @__PURE__ */ jsx10("span", { ref: contentRef, className: ellipsis && !expanded ? "sia-typography__ellipsis" : void 0, style: ellipsis && !expanded ? { "--sia-typography-rows": rows } : void 0, children: formatted }),
|
|
1280
1574
|
expandable && (overflow || expanded) ? /* @__PURE__ */ jsx10(Button, { variant: "link", size: "small", className: "sia-typography__action", "aria-expanded": expanded, disabled, onClick: () => setExpanded(!expanded), children: expanded ? "\u6536\u8D77" : "\u5C55\u5F00" }) : null,
|
|
1281
1575
|
editable ? /* @__PURE__ */ jsx10(Button, { ref: editRef, variant: "text", size: "small", className: "sia-typography__action", "aria-label": "\u7F16\u8F91\u6587\u672C", title: "\u7F16\u8F91", disabled, icon: /* @__PURE__ */ jsx10(Icon, { name: "edit", size: 14 }), onClick: () => {
|
|
@@ -1328,10 +1622,10 @@ var Typography = Object.assign(TypographyRoot, {
|
|
|
1328
1622
|
});
|
|
1329
1623
|
|
|
1330
1624
|
// src/components/FloatButton.tsx
|
|
1331
|
-
import { createContext, forwardRef, useContext, useEffect as
|
|
1625
|
+
import { createContext, forwardRef as forwardRef2, useContext, useEffect as useEffect5, useId as useId2, useRef as useRef7, useState as useState8 } from "react";
|
|
1332
1626
|
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1333
1627
|
var GroupShape = createContext(void 0);
|
|
1334
|
-
var FloatButtonRoot =
|
|
1628
|
+
var FloatButtonRoot = forwardRef2(function FloatButton({
|
|
1335
1629
|
icon,
|
|
1336
1630
|
description,
|
|
1337
1631
|
tooltip,
|
|
@@ -1384,8 +1678,8 @@ function FloatButtonGroup({
|
|
|
1384
1678
|
const [visible, setVisible] = useControllableState({ value: open, defaultValue: defaultOpen, onChange: onOpenChange });
|
|
1385
1679
|
const rootRef = useRef7(null);
|
|
1386
1680
|
const triggerRef = useRef7(null);
|
|
1387
|
-
const id =
|
|
1388
|
-
|
|
1681
|
+
const id = useId2();
|
|
1682
|
+
useEffect5(() => {
|
|
1389
1683
|
if (!trigger || !visible) return;
|
|
1390
1684
|
const close = (event) => {
|
|
1391
1685
|
if (!rootRef.current?.contains(event.target)) setVisible(false);
|
|
@@ -1439,8 +1733,8 @@ function FloatButtonGroup({
|
|
|
1439
1733
|
) });
|
|
1440
1734
|
}
|
|
1441
1735
|
function FloatButtonBackTop({ target, visibilityHeight = 400, behavior = "smooth", onClick, icon, tooltip = "\u8FD4\u56DE\u9876\u90E8", ...props }) {
|
|
1442
|
-
const [visible, setVisible] =
|
|
1443
|
-
|
|
1736
|
+
const [visible, setVisible] = useState8(false);
|
|
1737
|
+
useEffect5(() => {
|
|
1444
1738
|
const element = target ? target() : window;
|
|
1445
1739
|
if (!element) return;
|
|
1446
1740
|
const update = () => setVisible((element === window ? window.scrollY : element.scrollTop) >= visibilityHeight);
|