@uploadbox/react 0.1.0
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/generate-components.d.ts +5 -0
- package/dist/generate-components.d.ts.map +1 -0
- package/dist/generate-components.js +9 -0
- package/dist/generate-components.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/multipart.d.ts +25 -0
- package/dist/multipart.d.ts.map +1 -0
- package/dist/multipart.js +130 -0
- package/dist/multipart.js.map +1 -0
- package/dist/progress-tracker.d.ts +13 -0
- package/dist/progress-tracker.d.ts.map +1 -0
- package/dist/progress-tracker.js +93 -0
- package/dist/progress-tracker.js.map +1 -0
- package/dist/provider.d.ts +14 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +12 -0
- package/dist/provider.js.map +1 -0
- package/dist/retry.d.ts +5 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +47 -0
- package/dist/retry.js.map +1 -0
- package/dist/types.d.ts +86 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/upload-button.d.ts +4 -0
- package/dist/upload-button.d.ts.map +1 -0
- package/dist/upload-button.js +25 -0
- package/dist/upload-button.js.map +1 -0
- package/dist/upload-dropzone.d.ts +4 -0
- package/dist/upload-dropzone.d.ts.map +1 -0
- package/dist/upload-dropzone.js +47 -0
- package/dist/upload-dropzone.js.map +1 -0
- package/dist/use-uploadbox.d.ts +4 -0
- package/dist/use-uploadbox.d.ts.map +1 -0
- package/dist/use-uploadbox.js +246 -0
- package/dist/use-uploadbox.js.map +1 -0
- package/package.json +56 -0
- package/src/generate-components.ts +20 -0
- package/src/index.ts +22 -0
- package/src/multipart.ts +189 -0
- package/src/progress-tracker.ts +107 -0
- package/src/provider.tsx +34 -0
- package/src/retry.ts +62 -0
- package/src/styles.css +126 -0
- package/src/types.ts +96 -0
- package/src/upload-button.tsx +76 -0
- package/src/upload-dropzone.tsx +138 -0
- package/src/use-uploadbox.ts +333 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { FileRouter } from "@uploadbox/core";
|
|
2
|
+
import type { UploadButtonProps, UploadDropzoneProps } from "./types.js";
|
|
3
|
+
export declare function generateUploadButton<TRouter extends FileRouter>(): <TEndpoint extends keyof TRouter & string>(props: UploadButtonProps<TRouter, TEndpoint>) => React.JSX.Element;
|
|
4
|
+
export declare function generateUploadDropzone<TRouter extends FileRouter>(): <TEndpoint extends keyof TRouter & string>(props: UploadDropzoneProps<TRouter, TEndpoint>) => React.JSX.Element;
|
|
5
|
+
//# sourceMappingURL=generate-components.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-components.d.ts","sourceRoot":"","sources":["../src/generate-components.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAIzE,wBAAgB,oBAAoB,CAClC,OAAO,SAAS,UAAU,KAEH,CAAC,SAAS,SAAS,MAAM,OAAO,GAAG,MAAM,EAC9D,KAAK,EAAE,iBAAiB,CAAC,OAAO,EAAE,SAAS,CAAC,KACzC,KAAK,CAAC,GAAG,CAAC,OAAO,CACvB;AAED,wBAAgB,sBAAsB,CACpC,OAAO,SAAS,UAAU,KAED,CAAC,SAAS,SAAS,MAAM,OAAO,GAAG,MAAM,EAChE,KAAK,EAAE,mBAAmB,CAAC,OAAO,EAAE,SAAS,CAAC,KAC3C,KAAK,CAAC,GAAG,CAAC,OAAO,CACvB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { UploadButton } from "./upload-button.js";
|
|
2
|
+
import { UploadDropzone } from "./upload-dropzone.js";
|
|
3
|
+
export function generateUploadButton() {
|
|
4
|
+
return UploadButton;
|
|
5
|
+
}
|
|
6
|
+
export function generateUploadDropzone() {
|
|
7
|
+
return UploadDropzone;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=generate-components.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-components.js","sourceRoot":"","sources":["../src/generate-components.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,MAAM,UAAU,oBAAoB;IAGlC,OAAO,YAEe,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,sBAAsB;IAGpC,OAAO,cAEe,CAAC;AACzB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { UploadButton } from "./upload-button.js";
|
|
2
|
+
export { UploadDropzone } from "./upload-dropzone.js";
|
|
3
|
+
export { useUploadbox } from "./use-uploadbox.js";
|
|
4
|
+
export { generateUploadButton, generateUploadDropzone } from "./generate-components.js";
|
|
5
|
+
export { UploadboxProvider, useUploadboxConfig } from "./provider.js";
|
|
6
|
+
export type { UploadboxContextValue } from "./provider.js";
|
|
7
|
+
export { withRetry, DEFAULT_RETRY_CONFIG, isRetryableError } from "./retry.js";
|
|
8
|
+
export { ProgressTracker } from "./progress-tracker.js";
|
|
9
|
+
export { shouldUseMultipart, uploadFileMultipart } from "./multipart.js";
|
|
10
|
+
export type { UploadButtonProps, UploadDropzoneProps, UseUploadboxOpts, UseUploadboxReturn, UploadedFile, UploadProgressEvent, EndpointHelper, FileUploadStatus, FileProgress, EnhancedUploadProgressEvent, RetryConfig, } from "./types.js";
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACtE,YAAY,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACzE,YAAY,EACV,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,2BAA2B,EAC3B,WAAW,GACZ,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { UploadButton } from "./upload-button.js";
|
|
2
|
+
export { UploadDropzone } from "./upload-dropzone.js";
|
|
3
|
+
export { useUploadbox } from "./use-uploadbox.js";
|
|
4
|
+
export { generateUploadButton, generateUploadDropzone } from "./generate-components.js";
|
|
5
|
+
export { UploadboxProvider, useUploadboxConfig } from "./provider.js";
|
|
6
|
+
export { withRetry, DEFAULT_RETRY_CONFIG, isRetryableError } from "./retry.js";
|
|
7
|
+
export { ProgressTracker } from "./progress-tracker.js";
|
|
8
|
+
export { shouldUseMultipart, uploadFileMultipart } from "./multipart.js";
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEtE,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { RetryConfig } from "./types.js";
|
|
2
|
+
export declare function shouldUseMultipart(fileSize: number): boolean;
|
|
3
|
+
interface MultipartUploadOptions {
|
|
4
|
+
file: File;
|
|
5
|
+
routeKey: string;
|
|
6
|
+
fileInfo: {
|
|
7
|
+
name: string;
|
|
8
|
+
size: number;
|
|
9
|
+
type: string;
|
|
10
|
+
customMetadata?: Record<string, string>;
|
|
11
|
+
ttlSeconds?: number;
|
|
12
|
+
};
|
|
13
|
+
apiUrl?: string;
|
|
14
|
+
headers?: Record<string, string>;
|
|
15
|
+
retryConfig?: RetryConfig;
|
|
16
|
+
signal?: AbortSignal;
|
|
17
|
+
onProgress?: (loaded: number) => void;
|
|
18
|
+
onRetry?: () => void;
|
|
19
|
+
}
|
|
20
|
+
export declare function uploadFileMultipart(options: MultipartUploadOptions): Promise<{
|
|
21
|
+
key: string;
|
|
22
|
+
uploadId: string;
|
|
23
|
+
}>;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=multipart.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multipart.d.ts","sourceRoot":"","sources":["../src/multipart.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAQ9C,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED,UAAU,sBAAsB;IAC9B,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAkDD,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAkH5C"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { withRetry, DEFAULT_RETRY_CONFIG } from "./retry.js";
|
|
2
|
+
const DEFAULT_API_URL = "/api/uploadbox";
|
|
3
|
+
const MULTIPART_THRESHOLD = 10 * 1024 * 1024; // 10MB
|
|
4
|
+
const DEFAULT_PART_SIZE = 10 * 1024 * 1024; // 10MB
|
|
5
|
+
const MAX_CONCURRENT_PARTS = 4;
|
|
6
|
+
export function shouldUseMultipart(fileSize) {
|
|
7
|
+
return fileSize >= MULTIPART_THRESHOLD;
|
|
8
|
+
}
|
|
9
|
+
function uploadPartWithXhr(url, blob, onProgress, signal) {
|
|
10
|
+
return new Promise((resolve, reject) => {
|
|
11
|
+
const xhr = new XMLHttpRequest();
|
|
12
|
+
xhr.open("PUT", url);
|
|
13
|
+
if (signal) {
|
|
14
|
+
signal.addEventListener("abort", () => xhr.abort(), { once: true });
|
|
15
|
+
}
|
|
16
|
+
xhr.upload.addEventListener("progress", (event) => {
|
|
17
|
+
if (event.lengthComputable) {
|
|
18
|
+
onProgress?.(event.loaded);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
xhr.addEventListener("load", () => {
|
|
22
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
23
|
+
const etag = xhr.getResponseHeader("ETag");
|
|
24
|
+
if (!etag) {
|
|
25
|
+
reject(new Error("Missing ETag in upload response — check S3 CORS exposeHeaders"));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
resolve(etag);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
reject(new Error(`Part upload failed with status ${xhr.status}`));
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
xhr.addEventListener("error", () => reject(new Error("Part upload failed")));
|
|
35
|
+
xhr.addEventListener("abort", () => reject(new Error("Upload aborted")));
|
|
36
|
+
xhr.send(blob);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
export async function uploadFileMultipart(options) {
|
|
40
|
+
const { file, routeKey, fileInfo, apiUrl = DEFAULT_API_URL, headers, retryConfig, signal, onProgress, onRetry } = options;
|
|
41
|
+
// 1. Create multipart upload on server
|
|
42
|
+
const initRes = await fetch(apiUrl, {
|
|
43
|
+
method: "POST",
|
|
44
|
+
headers: { "Content-Type": "application/json", ...headers },
|
|
45
|
+
body: JSON.stringify({
|
|
46
|
+
action: "create-multipart",
|
|
47
|
+
routeKey,
|
|
48
|
+
file: fileInfo,
|
|
49
|
+
}),
|
|
50
|
+
signal,
|
|
51
|
+
});
|
|
52
|
+
if (!initRes.ok) {
|
|
53
|
+
const err = await initRes.json();
|
|
54
|
+
throw new Error(err.message || "Failed to create multipart upload");
|
|
55
|
+
}
|
|
56
|
+
const initData = await initRes.json();
|
|
57
|
+
const { fileKey, uploadId, parts, partSize } = initData;
|
|
58
|
+
// 2. Upload parts with concurrency
|
|
59
|
+
const completedParts = [];
|
|
60
|
+
const partLoaded = new Map();
|
|
61
|
+
let aborted = false;
|
|
62
|
+
const uploadPart = async (part) => {
|
|
63
|
+
if (signal?.aborted)
|
|
64
|
+
throw new Error("Upload aborted");
|
|
65
|
+
const start = (part.partNumber - 1) * partSize;
|
|
66
|
+
const end = Math.min(start + partSize, file.size);
|
|
67
|
+
const blob = file.slice(start, end);
|
|
68
|
+
const retry = retryConfig ?? DEFAULT_RETRY_CONFIG;
|
|
69
|
+
const etag = await withRetry(async () => {
|
|
70
|
+
return uploadPartWithXhr(part.url, blob, (loaded) => {
|
|
71
|
+
partLoaded.set(part.partNumber, loaded);
|
|
72
|
+
const totalLoaded = Array.from(partLoaded.values()).reduce((a, b) => a + b, 0);
|
|
73
|
+
onProgress?.(totalLoaded);
|
|
74
|
+
}, signal);
|
|
75
|
+
}, retry, () => {
|
|
76
|
+
partLoaded.set(part.partNumber, 0);
|
|
77
|
+
onRetry?.();
|
|
78
|
+
}, signal);
|
|
79
|
+
completedParts.push({ partNumber: part.partNumber, etag });
|
|
80
|
+
};
|
|
81
|
+
// Process parts with concurrency limit
|
|
82
|
+
const queue = [...parts];
|
|
83
|
+
const workers = [];
|
|
84
|
+
for (let i = 0; i < Math.min(MAX_CONCURRENT_PARTS, queue.length); i++) {
|
|
85
|
+
workers.push((async () => {
|
|
86
|
+
while (queue.length > 0 && !aborted) {
|
|
87
|
+
const part = queue.shift();
|
|
88
|
+
if (!part)
|
|
89
|
+
break;
|
|
90
|
+
await uploadPart(part);
|
|
91
|
+
}
|
|
92
|
+
})());
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
await Promise.all(workers);
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
aborted = true;
|
|
99
|
+
// Abort the multipart upload on failure
|
|
100
|
+
await fetch(apiUrl, {
|
|
101
|
+
method: "POST",
|
|
102
|
+
headers: { "Content-Type": "application/json", ...headers },
|
|
103
|
+
body: JSON.stringify({
|
|
104
|
+
action: "abort-multipart",
|
|
105
|
+
fileKey,
|
|
106
|
+
uploadId,
|
|
107
|
+
}),
|
|
108
|
+
}).catch(() => { });
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
111
|
+
// 3. Complete multipart upload on server
|
|
112
|
+
const completeRes = await fetch(apiUrl, {
|
|
113
|
+
method: "POST",
|
|
114
|
+
headers: { "Content-Type": "application/json", ...headers },
|
|
115
|
+
body: JSON.stringify({
|
|
116
|
+
action: "complete-multipart",
|
|
117
|
+
routeKey,
|
|
118
|
+
fileKey,
|
|
119
|
+
uploadId,
|
|
120
|
+
parts: completedParts,
|
|
121
|
+
}),
|
|
122
|
+
signal,
|
|
123
|
+
});
|
|
124
|
+
if (!completeRes.ok) {
|
|
125
|
+
const err = await completeRes.json();
|
|
126
|
+
throw new Error(err.message || "Failed to complete multipart upload");
|
|
127
|
+
}
|
|
128
|
+
return { key: fileKey, uploadId };
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=multipart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multipart.js","sourceRoot":"","sources":["../src/multipart.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { FileUploadStatus, EnhancedUploadProgressEvent } from "./types.js";
|
|
2
|
+
export declare class ProgressTracker {
|
|
3
|
+
private files;
|
|
4
|
+
private speedSamples;
|
|
5
|
+
init(fileId: string, name: string, size: number, type: string): void;
|
|
6
|
+
updateProgress(fileId: string, loaded: number): void;
|
|
7
|
+
setStatus(fileId: string, status: FileUploadStatus, error?: string): void;
|
|
8
|
+
setKey(fileId: string, key: string): void;
|
|
9
|
+
incrementRetry(fileId: string): void;
|
|
10
|
+
getSnapshot(): EnhancedUploadProgressEvent;
|
|
11
|
+
reset(): void;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=progress-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress-tracker.d.ts","sourceRoot":"","sources":["../src/progress-tracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,gBAAgB,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAS9F,qBAAa,eAAe;IAC1B,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,YAAY,CAAoC;IAExD,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAgBpE,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IA+BpD,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAYzE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAKzC,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAYpC,WAAW,IAAI,2BAA2B;IAa1C,KAAK,IAAI,IAAI;CAId"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
const SPEED_WINDOW_MS = 3000;
|
|
2
|
+
export class ProgressTracker {
|
|
3
|
+
files = new Map();
|
|
4
|
+
speedSamples = new Map();
|
|
5
|
+
init(fileId, name, size, type) {
|
|
6
|
+
this.files.set(fileId, {
|
|
7
|
+
fileId,
|
|
8
|
+
name,
|
|
9
|
+
size,
|
|
10
|
+
type,
|
|
11
|
+
status: "pending",
|
|
12
|
+
loaded: 0,
|
|
13
|
+
percent: 0,
|
|
14
|
+
speed: 0,
|
|
15
|
+
eta: 0,
|
|
16
|
+
retryCount: 0,
|
|
17
|
+
});
|
|
18
|
+
this.speedSamples.set(fileId, []);
|
|
19
|
+
}
|
|
20
|
+
updateProgress(fileId, loaded) {
|
|
21
|
+
const file = this.files.get(fileId);
|
|
22
|
+
if (!file)
|
|
23
|
+
return;
|
|
24
|
+
file.loaded = loaded;
|
|
25
|
+
file.percent = file.size > 0 ? Math.round((loaded / file.size) * 100) : 0;
|
|
26
|
+
file.status = "uploading";
|
|
27
|
+
// Update speed samples
|
|
28
|
+
const samples = this.speedSamples.get(fileId) ?? [];
|
|
29
|
+
const now = Date.now();
|
|
30
|
+
samples.push({ timestamp: now, loaded });
|
|
31
|
+
// Prune old samples
|
|
32
|
+
const cutoff = now - SPEED_WINDOW_MS;
|
|
33
|
+
const validSamples = samples.filter((s) => s.timestamp >= cutoff);
|
|
34
|
+
this.speedSamples.set(fileId, validSamples);
|
|
35
|
+
// Calculate speed from sliding window
|
|
36
|
+
if (validSamples.length >= 2) {
|
|
37
|
+
const oldest = validSamples[0];
|
|
38
|
+
const newest = validSamples[validSamples.length - 1];
|
|
39
|
+
const timeDiff = (newest.timestamp - oldest.timestamp) / 1000;
|
|
40
|
+
if (timeDiff > 0) {
|
|
41
|
+
file.speed = (newest.loaded - oldest.loaded) / timeDiff;
|
|
42
|
+
const remaining = file.size - loaded;
|
|
43
|
+
file.eta = file.speed > 0 ? remaining / file.speed : 0;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
setStatus(fileId, status, error) {
|
|
48
|
+
const file = this.files.get(fileId);
|
|
49
|
+
if (!file)
|
|
50
|
+
return;
|
|
51
|
+
file.status = status;
|
|
52
|
+
if (error)
|
|
53
|
+
file.error = error;
|
|
54
|
+
if (status === "complete") {
|
|
55
|
+
file.loaded = file.size;
|
|
56
|
+
file.percent = 100;
|
|
57
|
+
file.eta = 0;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
setKey(fileId, key) {
|
|
61
|
+
const file = this.files.get(fileId);
|
|
62
|
+
if (file)
|
|
63
|
+
file.key = key;
|
|
64
|
+
}
|
|
65
|
+
incrementRetry(fileId) {
|
|
66
|
+
const file = this.files.get(fileId);
|
|
67
|
+
if (!file)
|
|
68
|
+
return;
|
|
69
|
+
file.retryCount++;
|
|
70
|
+
file.status = "retrying";
|
|
71
|
+
file.loaded = 0;
|
|
72
|
+
file.percent = 0;
|
|
73
|
+
file.speed = 0;
|
|
74
|
+
file.eta = 0;
|
|
75
|
+
this.speedSamples.set(fileId, []);
|
|
76
|
+
}
|
|
77
|
+
getSnapshot() {
|
|
78
|
+
const allFiles = Array.from(this.files.values());
|
|
79
|
+
const totalSize = allFiles.reduce((sum, f) => sum + f.size, 0);
|
|
80
|
+
const totalLoaded = allFiles.reduce((sum, f) => sum + f.loaded, 0);
|
|
81
|
+
return {
|
|
82
|
+
loaded: totalLoaded,
|
|
83
|
+
total: totalSize,
|
|
84
|
+
percent: totalSize > 0 ? Math.round((totalLoaded / totalSize) * 100) : 0,
|
|
85
|
+
fileProgress: allFiles.map((f) => ({ ...f })),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
reset() {
|
|
89
|
+
this.files.clear();
|
|
90
|
+
this.speedSamples.clear();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=progress-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress-tracker.js","sourceRoot":"","sources":["../src/progress-tracker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export interface UploadboxContextValue {
|
|
3
|
+
/** Base URL for the upload API. Defaults to "/api/uploadbox". */
|
|
4
|
+
apiUrl?: string;
|
|
5
|
+
/** API key for hosted mode — sent as Authorization: Bearer. */
|
|
6
|
+
apiKey?: string;
|
|
7
|
+
/** Extra headers to include with every request. */
|
|
8
|
+
headers?: Record<string, string>;
|
|
9
|
+
}
|
|
10
|
+
export declare function UploadboxProvider({ children, ...config }: UploadboxContextValue & {
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare function useUploadboxConfig(): UploadboxContextValue;
|
|
14
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA6C,MAAM,OAAO,CAAC;AAElE,MAAM,WAAW,qBAAqB;IACpC,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAID,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,GAAG,MAAM,EACV,EAAE,qBAAqB,GAAG;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,2CAWvD;AAED,wBAAgB,kBAAkB,IAAI,qBAAqB,CAE1D"}
|
package/dist/provider.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext, useMemo } from "react";
|
|
4
|
+
const UploadboxContext = createContext({});
|
|
5
|
+
export function UploadboxProvider({ children, ...config }) {
|
|
6
|
+
const value = useMemo(() => ({ apiUrl: config.apiUrl, apiKey: config.apiKey, headers: config.headers }), [config.apiUrl, config.apiKey, config.headers]);
|
|
7
|
+
return (_jsx(UploadboxContext.Provider, { value: value, children: children }));
|
|
8
|
+
}
|
|
9
|
+
export function useUploadboxConfig() {
|
|
10
|
+
return useContext(UploadboxContext);
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAc,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAWlE,MAAM,gBAAgB,GAAG,aAAa,CAAwB,EAAE,CAAC,CAAC;AAElE,MAAM,UAAU,iBAAiB,CAAC,EAChC,QAAQ,EACR,GAAG,MAAM,EAC6C;IACtD,MAAM,KAAK,GAAG,OAAO,CACnB,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,EACjF,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAC/C,CAAC;IAEF,OAAO,CACL,KAAC,gBAAgB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YACpC,QAAQ,GACiB,CAC7B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,UAAU,CAAC,gBAAgB,CAAC,CAAC;AACtC,CAAC"}
|
package/dist/retry.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { RetryConfig } from "./types.js";
|
|
2
|
+
export declare const DEFAULT_RETRY_CONFIG: RetryConfig;
|
|
3
|
+
export declare function isRetryableError(status: number): boolean;
|
|
4
|
+
export declare function withRetry<T>(fn: (attempt: number) => Promise<T>, config: RetryConfig, onRetry?: (attempt: number, error: Error) => void, signal?: AbortSignal): Promise<T>;
|
|
5
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,eAAO,MAAM,oBAAoB,EAAE,WAKlC,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGxD;AAED,wBAAsB,SAAS,CAAC,CAAC,EAC/B,EAAE,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,EACnC,MAAM,EAAE,WAAW,EACnB,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,EACjD,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,CAAC,CAAC,CA0CZ"}
|
package/dist/retry.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export const DEFAULT_RETRY_CONFIG = {
|
|
2
|
+
maxRetries: 3,
|
|
3
|
+
initialDelayMs: 1000,
|
|
4
|
+
backoffMultiplier: 2,
|
|
5
|
+
maxDelayMs: 30000,
|
|
6
|
+
};
|
|
7
|
+
export function isRetryableError(status) {
|
|
8
|
+
if (status === 0 || status === 408 || status === 429)
|
|
9
|
+
return true;
|
|
10
|
+
return status >= 500 && status < 600;
|
|
11
|
+
}
|
|
12
|
+
export async function withRetry(fn, config, onRetry, signal) {
|
|
13
|
+
let lastError;
|
|
14
|
+
for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
|
|
15
|
+
if (signal?.aborted) {
|
|
16
|
+
throw new Error("Upload aborted");
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
return await fn(attempt);
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
23
|
+
if (attempt >= config.maxRetries)
|
|
24
|
+
break;
|
|
25
|
+
// Check if the error contains a retryable status
|
|
26
|
+
const statusMatch = lastError.message.match(/status (\d+)/);
|
|
27
|
+
if (statusMatch) {
|
|
28
|
+
const status = parseInt(statusMatch[1], 10);
|
|
29
|
+
if (!isRetryableError(status))
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
const delay = Math.min(config.initialDelayMs * Math.pow(config.backoffMultiplier, attempt), config.maxDelayMs);
|
|
33
|
+
// Add jitter: 0.5x to 1.5x of delay
|
|
34
|
+
const jitteredDelay = delay * (0.5 + Math.random());
|
|
35
|
+
onRetry?.(attempt + 1, lastError);
|
|
36
|
+
await new Promise((resolve, reject) => {
|
|
37
|
+
const timeout = setTimeout(resolve, jitteredDelay);
|
|
38
|
+
signal?.addEventListener("abort", () => {
|
|
39
|
+
clearTimeout(timeout);
|
|
40
|
+
reject(new Error("Upload aborted"));
|
|
41
|
+
}, { once: true });
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
throw lastError ?? new Error("Retry failed");
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,oBAAoB,GAAgB;IAC/C,UAAU,EAAE,CAAC;IACb,cAAc,EAAE,IAAI;IACpB,iBAAiB,EAAE,CAAC;IACpB,UAAU,EAAE,KAAK;CAClB,CAAC;AAEF,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,IAAI,MAAM,KAAK,CAAC,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IAClE,OAAO,MAAM,IAAI,GAAG,IAAI,MAAM,GAAG,GAAG,CAAC;AACvC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,EAAmC,EACnC,MAAmB,EACnB,OAAiD,EACjD,MAAoB;IAEpB,IAAI,SAA4B,CAAC;IAEjC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,MAAM,CAAC,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QAC9D,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;QACpC,CAAC;QAED,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,SAAS,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAEhE,IAAI,OAAO,IAAI,MAAM,CAAC,UAAU;gBAAE,MAAM;YAExC,iDAAiD;YACjD,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;YAC5D,IAAI,WAAW,EAAE,CAAC;gBAChB,MAAM,MAAM,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,CAAC;gBAC7C,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC;oBAAE,MAAM;YACvC,CAAC;YAED,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CACpB,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,iBAAiB,EAAE,OAAO,CAAC,EACnE,MAAM,CAAC,UAAU,CAClB,CAAC;YACF,oCAAoC;YACpC,MAAM,aAAa,GAAG,KAAK,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YAEpD,OAAO,EAAE,CAAC,OAAO,GAAG,CAAC,EAAE,SAAS,CAAC,CAAC;YAElC,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBAC1C,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;gBACnD,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;oBACrC,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,MAAM,CAAC,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC;gBACtC,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACrB,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,MAAM,SAAS,IAAI,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;AAC/C,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { FileRouter, RouterConfig } from "@uploadbox/core";
|
|
2
|
+
export type EndpointHelper<TRouter extends FileRouter> = keyof TRouter & string;
|
|
3
|
+
export interface UploadProgressEvent {
|
|
4
|
+
loaded: number;
|
|
5
|
+
total: number;
|
|
6
|
+
percent: number;
|
|
7
|
+
}
|
|
8
|
+
export interface UploadedFile {
|
|
9
|
+
key: string;
|
|
10
|
+
name: string;
|
|
11
|
+
size: number;
|
|
12
|
+
type: string;
|
|
13
|
+
url: string;
|
|
14
|
+
customMetadata?: Record<string, string>;
|
|
15
|
+
}
|
|
16
|
+
export type FileUploadStatus = "pending" | "uploading" | "retrying" | "complete" | "error";
|
|
17
|
+
export interface FileProgress {
|
|
18
|
+
fileId: string;
|
|
19
|
+
name: string;
|
|
20
|
+
size: number;
|
|
21
|
+
type: string;
|
|
22
|
+
status: FileUploadStatus;
|
|
23
|
+
loaded: number;
|
|
24
|
+
percent: number;
|
|
25
|
+
speed: number;
|
|
26
|
+
eta: number;
|
|
27
|
+
error?: string;
|
|
28
|
+
retryCount: number;
|
|
29
|
+
key?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface EnhancedUploadProgressEvent extends UploadProgressEvent {
|
|
32
|
+
fileProgress: FileProgress[];
|
|
33
|
+
}
|
|
34
|
+
export interface RetryConfig {
|
|
35
|
+
maxRetries: number;
|
|
36
|
+
initialDelayMs: number;
|
|
37
|
+
backoffMultiplier: number;
|
|
38
|
+
maxDelayMs: number;
|
|
39
|
+
}
|
|
40
|
+
export interface UseUploadboxOpts<TRouter extends FileRouter, TEndpoint extends keyof TRouter & string> {
|
|
41
|
+
endpoint: TEndpoint;
|
|
42
|
+
onClientUploadComplete?: (files: UploadedFile[]) => void;
|
|
43
|
+
onUploadError?: (error: Error) => void;
|
|
44
|
+
onUploadProgress?: (progress: EnhancedUploadProgressEvent) => void;
|
|
45
|
+
onBeforeUploadBegin?: (files: File[]) => File[];
|
|
46
|
+
headers?: Record<string, string>;
|
|
47
|
+
getFileMetadata?: (file: File) => Record<string, string>;
|
|
48
|
+
ttlSeconds?: number;
|
|
49
|
+
retry?: RetryConfig | false;
|
|
50
|
+
}
|
|
51
|
+
export interface UseUploadboxReturn {
|
|
52
|
+
startUpload: (files: File[]) => Promise<UploadedFile[] | undefined>;
|
|
53
|
+
isUploading: boolean;
|
|
54
|
+
progress: number;
|
|
55
|
+
routeConfig: RouterConfig[string] | undefined;
|
|
56
|
+
fileProgress: FileProgress[];
|
|
57
|
+
abort: () => void;
|
|
58
|
+
}
|
|
59
|
+
export interface UploadButtonProps<TRouter extends FileRouter, TEndpoint extends keyof TRouter & string> {
|
|
60
|
+
endpoint: TEndpoint;
|
|
61
|
+
onClientUploadComplete?: (files: UploadedFile[]) => void;
|
|
62
|
+
onUploadError?: (error: Error) => void;
|
|
63
|
+
onUploadProgress?: (progress: UploadProgressEvent) => void;
|
|
64
|
+
onBeforeUploadBegin?: (files: File[]) => File[];
|
|
65
|
+
className?: string;
|
|
66
|
+
disabled?: boolean;
|
|
67
|
+
content?: {
|
|
68
|
+
button?: string;
|
|
69
|
+
allowedContent?: string;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export interface UploadDropzoneProps<TRouter extends FileRouter, TEndpoint extends keyof TRouter & string> {
|
|
73
|
+
endpoint: TEndpoint;
|
|
74
|
+
onClientUploadComplete?: (files: UploadedFile[]) => void;
|
|
75
|
+
onUploadError?: (error: Error) => void;
|
|
76
|
+
onUploadProgress?: (progress: UploadProgressEvent) => void;
|
|
77
|
+
onBeforeUploadBegin?: (files: File[]) => File[];
|
|
78
|
+
className?: string;
|
|
79
|
+
disabled?: boolean;
|
|
80
|
+
content?: {
|
|
81
|
+
label?: string;
|
|
82
|
+
allowedContent?: string;
|
|
83
|
+
button?: string;
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { FileRouter } from "@uploadbox/core";
|
|
2
|
+
import type { UploadButtonProps } from "./types.js";
|
|
3
|
+
export declare function UploadButton<TRouter extends FileRouter, TEndpoint extends keyof TRouter & string>(props: UploadButtonProps<TRouter, TEndpoint>): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
//# sourceMappingURL=upload-button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-button.d.ts","sourceRoot":"","sources":["../src/upload-button.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAGpD,wBAAgB,YAAY,CAC1B,OAAO,SAAS,UAAU,EAC1B,SAAS,SAAS,MAAM,OAAO,GAAG,MAAM,EACxC,KAAK,EAAE,iBAAiB,CAAC,OAAO,EAAE,SAAS,CAAC,2CAiE7C"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useRef, useCallback } from "react";
|
|
4
|
+
import { useUploadbox } from "./use-uploadbox.js";
|
|
5
|
+
export function UploadButton(props) {
|
|
6
|
+
const { endpoint, onClientUploadComplete, onUploadError, onUploadProgress, onBeforeUploadBegin, className, disabled, content, } = props;
|
|
7
|
+
const inputRef = useRef(null);
|
|
8
|
+
const { startUpload, isUploading, progress } = useUploadbox(endpoint, { onClientUploadComplete, onUploadError, onUploadProgress, onBeforeUploadBegin });
|
|
9
|
+
const handleClick = useCallback(() => {
|
|
10
|
+
inputRef.current?.click();
|
|
11
|
+
}, []);
|
|
12
|
+
const handleChange = useCallback(async (e) => {
|
|
13
|
+
const files = Array.from(e.target.files ?? []);
|
|
14
|
+
if (files.length > 0) {
|
|
15
|
+
await startUpload(files);
|
|
16
|
+
}
|
|
17
|
+
// Reset input so the same file can be selected again
|
|
18
|
+
if (inputRef.current)
|
|
19
|
+
inputRef.current.value = "";
|
|
20
|
+
}, [startUpload]);
|
|
21
|
+
return (_jsxs("div", { className: `uploadbox-button-wrapper ${className ?? ""}`, children: [_jsx("input", { ref: inputRef, type: "file", multiple: true, onChange: handleChange, style: { display: "none" }, disabled: disabled || isUploading }), _jsx("button", { type: "button", className: "uploadbox-button", onClick: handleClick, disabled: disabled || isUploading, children: isUploading
|
|
22
|
+
? `Uploading... ${progress}%`
|
|
23
|
+
: content?.button ?? "Upload Files" }), isUploading && (_jsx("div", { className: "uploadbox-progress-bar", children: _jsx("div", { className: "uploadbox-progress-bar-fill", style: { width: `${progress}%` } }) }))] }));
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=upload-button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-button.js","sourceRoot":"","sources":["../src/upload-button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAGnD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,UAAU,YAAY,CAG1B,KAA4C;IAC5C,MAAM,EACJ,QAAQ,EACR,sBAAsB,EACtB,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,SAAS,EACT,QAAQ,EACR,OAAO,GACR,GAAG,KAAK,CAAC;IAEV,MAAM,QAAQ,GAAG,MAAM,CAAmB,IAAI,CAAC,CAAC;IAEhD,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,YAAY,CACzD,QAAQ,EACR,EAAE,sBAAsB,EAAE,aAAa,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,CACjF,CAAC;IAEF,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,EAAE;QACnC,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;IAC5B,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,YAAY,GAAG,WAAW,CAC9B,KAAK,EAAE,CAAsC,EAAE,EAAE;QAC/C,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;QAC/C,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;QACD,qDAAqD;QACrD,IAAI,QAAQ,CAAC,OAAO;YAAE,QAAQ,CAAC,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC;IACpD,CAAC,EACD,CAAC,WAAW,CAAC,CACd,CAAC;IAEF,OAAO,CACL,eAAK,SAAS,EAAE,4BAA4B,SAAS,IAAI,EAAE,EAAE,aAC3D,gBACE,GAAG,EAAE,QAAQ,EACb,IAAI,EAAC,MAAM,EACX,QAAQ,QACR,QAAQ,EAAE,YAAY,EACtB,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAC1B,QAAQ,EAAE,QAAQ,IAAI,WAAW,GACjC,EACF,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,kBAAkB,EAC5B,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,QAAQ,IAAI,WAAW,YAEhC,WAAW;oBACV,CAAC,CAAC,gBAAgB,QAAQ,GAAG;oBAC7B,CAAC,CAAC,OAAO,EAAE,MAAM,IAAI,cAAc,GAC9B,EACR,WAAW,IAAI,CACd,cAAK,SAAS,EAAC,wBAAwB,YACrC,cACE,SAAS,EAAC,6BAA6B,EACvC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,QAAQ,GAAG,EAAE,GAChC,GACE,CACP,IACG,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { FileRouter } from "@uploadbox/core";
|
|
2
|
+
import type { UploadDropzoneProps } from "./types.js";
|
|
3
|
+
export declare function UploadDropzone<TRouter extends FileRouter, TEndpoint extends keyof TRouter & string>(props: UploadDropzoneProps<TRouter, TEndpoint>): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
//# sourceMappingURL=upload-dropzone.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-dropzone.d.ts","sourceRoot":"","sources":["../src/upload-dropzone.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAKtD,wBAAgB,cAAc,CAC5B,OAAO,SAAS,UAAU,EAC1B,SAAS,SAAS,MAAM,OAAO,GAAG,MAAM,EACxC,KAAK,EAAE,mBAAmB,CAAC,OAAO,EAAE,SAAS,CAAC,2CA4H/C"}
|