@uploadista/react 0.0.3
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/.turbo/turbo-check.log +89 -0
- package/FLOW_UPLOAD.md +307 -0
- package/LICENSE +21 -0
- package/README.md +318 -0
- package/package.json +35 -0
- package/src/components/flow-upload-list.tsx +614 -0
- package/src/components/flow-upload-zone.tsx +441 -0
- package/src/components/upload-list.tsx +626 -0
- package/src/components/upload-zone.tsx +545 -0
- package/src/components/uploadista-provider.tsx +190 -0
- package/src/hooks/use-drag-drop.ts +404 -0
- package/src/hooks/use-flow-upload.ts +568 -0
- package/src/hooks/use-multi-flow-upload.ts +477 -0
- package/src/hooks/use-multi-upload.ts +691 -0
- package/src/hooks/use-upload-metrics.ts +585 -0
- package/src/hooks/use-upload.ts +411 -0
- package/src/hooks/use-uploadista-client.ts +145 -0
- package/src/index.ts +87 -0
- package/tsconfig.json +11 -0
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BrowserUploadInput,
|
|
3
|
+
ChunkMetrics,
|
|
4
|
+
PerformanceInsights,
|
|
5
|
+
UploadistaEvent,
|
|
6
|
+
UploadSessionMetrics,
|
|
7
|
+
} from "@uploadista/client-browser";
|
|
8
|
+
import type { UploadFile } from "@uploadista/core/types";
|
|
9
|
+
import { UploadEventType } from "@uploadista/core/types";
|
|
10
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
11
|
+
import { useUploadistaContext } from "../components/uploadista-provider";
|
|
12
|
+
|
|
13
|
+
export type UploadStatus =
|
|
14
|
+
| "idle"
|
|
15
|
+
| "uploading"
|
|
16
|
+
| "success"
|
|
17
|
+
| "error"
|
|
18
|
+
| "aborted";
|
|
19
|
+
|
|
20
|
+
export interface UploadState {
|
|
21
|
+
status: UploadStatus;
|
|
22
|
+
progress: number;
|
|
23
|
+
bytesUploaded: number;
|
|
24
|
+
totalBytes: number | null;
|
|
25
|
+
error: Error | null;
|
|
26
|
+
result: UploadFile | null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface UseUploadOptions {
|
|
30
|
+
/**
|
|
31
|
+
* Upload metadata to attach to the file
|
|
32
|
+
*/
|
|
33
|
+
metadata?: Record<string, string>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Whether to defer the upload size calculation
|
|
37
|
+
*/
|
|
38
|
+
uploadLengthDeferred?: boolean;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Manual upload size override
|
|
42
|
+
*/
|
|
43
|
+
uploadSize?: number;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Called when upload progress updates
|
|
47
|
+
*/
|
|
48
|
+
onProgress?: (
|
|
49
|
+
progress: number,
|
|
50
|
+
bytesUploaded: number,
|
|
51
|
+
totalBytes: number | null,
|
|
52
|
+
) => void;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Called when a chunk completes
|
|
56
|
+
*/
|
|
57
|
+
onChunkComplete?: (
|
|
58
|
+
chunkSize: number,
|
|
59
|
+
bytesAccepted: number,
|
|
60
|
+
bytesTotal: number | null,
|
|
61
|
+
) => void;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Called when upload succeeds
|
|
65
|
+
*/
|
|
66
|
+
onSuccess?: (result: UploadFile) => void;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Called when upload fails
|
|
70
|
+
*/
|
|
71
|
+
onError?: (error: Error) => void;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Called when upload is aborted
|
|
75
|
+
*/
|
|
76
|
+
onAbort?: () => void;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Custom retry logic
|
|
80
|
+
*/
|
|
81
|
+
onShouldRetry?: (error: Error, retryAttempt: number) => boolean;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface UploadMetrics {
|
|
85
|
+
/**
|
|
86
|
+
* Get performance insights from the upload client
|
|
87
|
+
*/
|
|
88
|
+
getInsights: () => PerformanceInsights;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Export detailed metrics from the upload client
|
|
92
|
+
*/
|
|
93
|
+
exportMetrics: () => {
|
|
94
|
+
session: Partial<UploadSessionMetrics>;
|
|
95
|
+
chunks: ChunkMetrics[];
|
|
96
|
+
insights: PerformanceInsights;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Get current network metrics
|
|
101
|
+
*/
|
|
102
|
+
getNetworkMetrics: () => unknown;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get current network condition
|
|
106
|
+
*/
|
|
107
|
+
getNetworkCondition: () => unknown;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Reset all metrics
|
|
111
|
+
*/
|
|
112
|
+
resetMetrics: () => void;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface UseUploadReturn {
|
|
116
|
+
/**
|
|
117
|
+
* Current upload state
|
|
118
|
+
*/
|
|
119
|
+
state: UploadState;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Start uploading a file
|
|
123
|
+
*/
|
|
124
|
+
upload: (file: BrowserUploadInput) => void;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Abort the current upload
|
|
128
|
+
*/
|
|
129
|
+
abort: () => void;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Reset the upload state to idle
|
|
133
|
+
*/
|
|
134
|
+
reset: () => void;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Retry the last failed upload
|
|
138
|
+
*/
|
|
139
|
+
retry: () => void;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Whether an upload is currently active
|
|
143
|
+
*/
|
|
144
|
+
isUploading: boolean;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Whether the upload can be retried
|
|
148
|
+
*/
|
|
149
|
+
canRetry: boolean;
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Upload metrics and performance insights from the client
|
|
153
|
+
*/
|
|
154
|
+
metrics: UploadMetrics;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const initialState: UploadState = {
|
|
158
|
+
status: "idle",
|
|
159
|
+
progress: 0,
|
|
160
|
+
bytesUploaded: 0,
|
|
161
|
+
totalBytes: null,
|
|
162
|
+
error: null,
|
|
163
|
+
result: null,
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* React hook for managing individual file uploads with full state management.
|
|
168
|
+
* Provides upload progress tracking, error handling, abort functionality, and retry logic.
|
|
169
|
+
*
|
|
170
|
+
* Must be used within an UploadistaProvider.
|
|
171
|
+
*
|
|
172
|
+
* @param options - Upload configuration and event handlers
|
|
173
|
+
* @returns Upload state and control methods
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```tsx
|
|
177
|
+
* function MyComponent() {
|
|
178
|
+
* const upload = useUpload({
|
|
179
|
+
* onSuccess: (result) => console.log('Upload complete:', result),
|
|
180
|
+
* onError: (error) => console.error('Upload failed:', error),
|
|
181
|
+
* onProgress: (progress) => console.log('Progress:', progress + '%'),
|
|
182
|
+
* });
|
|
183
|
+
*
|
|
184
|
+
* return (
|
|
185
|
+
* <div>
|
|
186
|
+
* <input
|
|
187
|
+
* type="file"
|
|
188
|
+
* onChange={(e) => {
|
|
189
|
+
* const file = e.target.files?.[0];
|
|
190
|
+
* if (file) upload.upload(file);
|
|
191
|
+
* }}
|
|
192
|
+
* />
|
|
193
|
+
* {upload.isUploading && <div>Progress: {upload.state.progress}%</div>}
|
|
194
|
+
* {upload.state.error && <div>Error: {upload.state.error.message}</div>}
|
|
195
|
+
* {upload.canRetry && <button onClick={upload.retry}>Retry</button>}
|
|
196
|
+
* <button onClick={upload.abort} disabled={!upload.isUploading}>Abort</button>
|
|
197
|
+
* </div>
|
|
198
|
+
* );
|
|
199
|
+
* }
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
export function useUpload(options: UseUploadOptions = {}): UseUploadReturn {
|
|
203
|
+
const uploadClient = useUploadistaContext();
|
|
204
|
+
const [state, setState] = useState<UploadState>(initialState);
|
|
205
|
+
const abortControllerRef = useRef<{ abort: () => void } | null>(null);
|
|
206
|
+
const lastFileRef = useRef<BrowserUploadInput | null>(null);
|
|
207
|
+
|
|
208
|
+
const updateState = useCallback((update: Partial<UploadState>) => {
|
|
209
|
+
setState((prev) => ({ ...prev, ...update }));
|
|
210
|
+
}, []);
|
|
211
|
+
|
|
212
|
+
const reset = useCallback(() => {
|
|
213
|
+
if (abortControllerRef.current) {
|
|
214
|
+
abortControllerRef.current.abort();
|
|
215
|
+
abortControllerRef.current = null;
|
|
216
|
+
}
|
|
217
|
+
setState(initialState);
|
|
218
|
+
lastFileRef.current = null;
|
|
219
|
+
}, []);
|
|
220
|
+
|
|
221
|
+
const abort = useCallback(() => {
|
|
222
|
+
if (abortControllerRef.current) {
|
|
223
|
+
abortControllerRef.current.abort();
|
|
224
|
+
abortControllerRef.current = null;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
updateState({
|
|
228
|
+
status: "aborted",
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
options.onAbort?.();
|
|
232
|
+
}, [options, updateState]);
|
|
233
|
+
|
|
234
|
+
const upload = useCallback(
|
|
235
|
+
(file: BrowserUploadInput) => {
|
|
236
|
+
// Reset any previous state but keep the file reference for retries
|
|
237
|
+
setState({
|
|
238
|
+
...initialState,
|
|
239
|
+
status: "uploading",
|
|
240
|
+
totalBytes: file instanceof File ? file.size : null,
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
lastFileRef.current = file;
|
|
244
|
+
|
|
245
|
+
// Start the upload and handle the promise
|
|
246
|
+
const uploadPromise = uploadClient.client.upload(file, {
|
|
247
|
+
metadata: options.metadata,
|
|
248
|
+
uploadLengthDeferred: options.uploadLengthDeferred,
|
|
249
|
+
uploadSize: options.uploadSize,
|
|
250
|
+
|
|
251
|
+
onStart: ({ uploadId }) => {
|
|
252
|
+
currentUploadIdRef.current = uploadId;
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
onProgress: (
|
|
256
|
+
_uploadId: string,
|
|
257
|
+
bytesUploaded: number,
|
|
258
|
+
totalBytes: number | null,
|
|
259
|
+
) => {
|
|
260
|
+
const progress = totalBytes
|
|
261
|
+
? Math.round((bytesUploaded / totalBytes) * 100)
|
|
262
|
+
: 0;
|
|
263
|
+
|
|
264
|
+
updateState({
|
|
265
|
+
progress,
|
|
266
|
+
bytesUploaded,
|
|
267
|
+
totalBytes,
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
options.onProgress?.(progress, bytesUploaded, totalBytes);
|
|
271
|
+
},
|
|
272
|
+
|
|
273
|
+
onChunkComplete: (
|
|
274
|
+
chunkSize: number,
|
|
275
|
+
bytesAccepted: number,
|
|
276
|
+
bytesTotal: number | null,
|
|
277
|
+
) => {
|
|
278
|
+
options.onChunkComplete?.(chunkSize, bytesAccepted, bytesTotal);
|
|
279
|
+
},
|
|
280
|
+
|
|
281
|
+
onSuccess: (result: UploadFile) => {
|
|
282
|
+
updateState({
|
|
283
|
+
status: "success",
|
|
284
|
+
result,
|
|
285
|
+
progress: 100,
|
|
286
|
+
bytesUploaded: result.size || 0,
|
|
287
|
+
totalBytes: result.size || null,
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
options.onSuccess?.(result);
|
|
291
|
+
abortControllerRef.current = null;
|
|
292
|
+
},
|
|
293
|
+
|
|
294
|
+
onError: (error: Error) => {
|
|
295
|
+
updateState({
|
|
296
|
+
status: "error",
|
|
297
|
+
error,
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
options.onError?.(error);
|
|
301
|
+
abortControllerRef.current = null;
|
|
302
|
+
},
|
|
303
|
+
|
|
304
|
+
onShouldRetry: options.onShouldRetry,
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// Handle the promise to get the abort controller
|
|
308
|
+
uploadPromise
|
|
309
|
+
.then((controller) => {
|
|
310
|
+
abortControllerRef.current = controller;
|
|
311
|
+
})
|
|
312
|
+
.catch((error) => {
|
|
313
|
+
updateState({
|
|
314
|
+
status: "error",
|
|
315
|
+
error: error as Error,
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
options.onError?.(error as Error);
|
|
319
|
+
abortControllerRef.current = null;
|
|
320
|
+
});
|
|
321
|
+
},
|
|
322
|
+
[uploadClient, options, updateState],
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
const retry = useCallback(() => {
|
|
326
|
+
if (
|
|
327
|
+
lastFileRef.current &&
|
|
328
|
+
(state.status === "error" || state.status === "aborted")
|
|
329
|
+
) {
|
|
330
|
+
upload(lastFileRef.current);
|
|
331
|
+
}
|
|
332
|
+
}, [upload, state.status]);
|
|
333
|
+
|
|
334
|
+
// Store current upload ID for event matching
|
|
335
|
+
const currentUploadIdRef = useRef<string | null>(null);
|
|
336
|
+
|
|
337
|
+
// Subscribe to events from context (WebSocket events)
|
|
338
|
+
useEffect(() => {
|
|
339
|
+
const unsubscribe = uploadClient.subscribeToEvents(
|
|
340
|
+
(event: UploadistaEvent) => {
|
|
341
|
+
// Handle upload progress events
|
|
342
|
+
const uploadEvent = event as {
|
|
343
|
+
type: string;
|
|
344
|
+
data?: { id: string; progress: number; total: number };
|
|
345
|
+
};
|
|
346
|
+
if (
|
|
347
|
+
uploadEvent.type === UploadEventType.UPLOAD_PROGRESS &&
|
|
348
|
+
uploadEvent.data
|
|
349
|
+
) {
|
|
350
|
+
const {
|
|
351
|
+
id: uploadId,
|
|
352
|
+
progress: bytesUploaded,
|
|
353
|
+
total: totalBytes,
|
|
354
|
+
} = uploadEvent.data;
|
|
355
|
+
|
|
356
|
+
if (uploadId !== currentUploadIdRef.current) {
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Update state for this upload
|
|
361
|
+
// Note: We update for all uploads since we don't track upload IDs in single upload mode
|
|
362
|
+
const progress = totalBytes
|
|
363
|
+
? Math.round((bytesUploaded / totalBytes) * 100)
|
|
364
|
+
: 0;
|
|
365
|
+
|
|
366
|
+
setState((prev) => {
|
|
367
|
+
// Only update if we're currently uploading
|
|
368
|
+
if (prev.status === "uploading") {
|
|
369
|
+
return {
|
|
370
|
+
...prev,
|
|
371
|
+
progress,
|
|
372
|
+
bytesUploaded,
|
|
373
|
+
totalBytes,
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
return prev;
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
options.onProgress?.(progress, bytesUploaded, totalBytes);
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
);
|
|
383
|
+
|
|
384
|
+
return unsubscribe;
|
|
385
|
+
}, [uploadClient, options]);
|
|
386
|
+
|
|
387
|
+
const isUploading = state.status === "uploading";
|
|
388
|
+
const canRetry =
|
|
389
|
+
(state.status === "error" || state.status === "aborted") &&
|
|
390
|
+
lastFileRef.current !== null;
|
|
391
|
+
|
|
392
|
+
// Create metrics object that delegates to the upload client
|
|
393
|
+
const metrics: UploadMetrics = {
|
|
394
|
+
getInsights: () => uploadClient.client.getChunkingInsights(),
|
|
395
|
+
exportMetrics: () => uploadClient.client.exportMetrics(),
|
|
396
|
+
getNetworkMetrics: () => uploadClient.client.getNetworkMetrics(),
|
|
397
|
+
getNetworkCondition: () => uploadClient.client.getNetworkCondition(),
|
|
398
|
+
resetMetrics: () => uploadClient.client.resetMetrics(),
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
return {
|
|
402
|
+
state,
|
|
403
|
+
upload,
|
|
404
|
+
abort,
|
|
405
|
+
reset,
|
|
406
|
+
retry,
|
|
407
|
+
isUploading,
|
|
408
|
+
canRetry,
|
|
409
|
+
metrics,
|
|
410
|
+
};
|
|
411
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createUploadistaClient,
|
|
3
|
+
type UploadistaClientOptions,
|
|
4
|
+
} from "@uploadista/client-browser";
|
|
5
|
+
import { useMemo, useRef } from "react";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Configuration options for the uploadista client hook.
|
|
9
|
+
* Extends the base client options with React-specific behavior.
|
|
10
|
+
*
|
|
11
|
+
* @property onEvent - Global event handler for all upload and flow events
|
|
12
|
+
* @property baseUrl - API base URL for uploads
|
|
13
|
+
* @property storageId - Default storage identifier
|
|
14
|
+
* @property chunkSize - Size of upload chunks in bytes
|
|
15
|
+
* @property storeFingerprintForResuming - Enable resumable uploads
|
|
16
|
+
* @property retryDelays - Array of retry delays in milliseconds
|
|
17
|
+
* @property parallelUploads - Maximum number of parallel uploads
|
|
18
|
+
* @property uploadStrategy - Upload strategy (sequential, parallel, adaptive)
|
|
19
|
+
* @property smartChunking - Enable dynamic chunk size adjustment
|
|
20
|
+
* @property networkMonitoring - Enable network condition monitoring
|
|
21
|
+
*/
|
|
22
|
+
export interface UseUploadistaClientOptions extends UploadistaClientOptions {
|
|
23
|
+
/**
|
|
24
|
+
* Global event handler for all upload and flow events from this client
|
|
25
|
+
*/
|
|
26
|
+
onEvent?: UploadistaClientOptions["onEvent"];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Return value from the useUploadistaClient hook.
|
|
31
|
+
*
|
|
32
|
+
* @property client - Configured uploadista client instance (stable across re-renders)
|
|
33
|
+
* @property config - Current client configuration options
|
|
34
|
+
*/
|
|
35
|
+
export interface UseUploadistaClientReturn {
|
|
36
|
+
/**
|
|
37
|
+
* The uploadista client instance
|
|
38
|
+
*/
|
|
39
|
+
client: ReturnType<typeof createUploadistaClient>;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Current configuration of the client
|
|
43
|
+
*/
|
|
44
|
+
config: UseUploadistaClientOptions;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* React hook for creating and managing an uploadista client instance.
|
|
49
|
+
* The client instance is memoized and stable across re-renders, only being
|
|
50
|
+
* recreated when configuration options change.
|
|
51
|
+
*
|
|
52
|
+
* This hook is typically used internally by UploadistaProvider, but can be
|
|
53
|
+
* used directly for advanced use cases requiring multiple client instances.
|
|
54
|
+
*
|
|
55
|
+
* @param options - Upload client configuration options
|
|
56
|
+
* @returns Object containing the stable client instance and current configuration
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```tsx
|
|
60
|
+
* // Basic client setup
|
|
61
|
+
* function MyUploadComponent() {
|
|
62
|
+
* const { client, config } = useUploadistaClient({
|
|
63
|
+
* baseUrl: 'https://api.example.com',
|
|
64
|
+
* storageId: 'default-storage',
|
|
65
|
+
* chunkSize: 1024 * 1024, // 1MB chunks
|
|
66
|
+
* storeFingerprintForResuming: true,
|
|
67
|
+
* onEvent: (event) => {
|
|
68
|
+
* console.log('Upload event:', event);
|
|
69
|
+
* }
|
|
70
|
+
* });
|
|
71
|
+
*
|
|
72
|
+
* // Use client directly
|
|
73
|
+
* const handleUpload = async (file: File) => {
|
|
74
|
+
* await client.upload(file, {
|
|
75
|
+
* onSuccess: (result) => console.log('Uploaded:', result),
|
|
76
|
+
* onError: (error) => console.error('Failed:', error),
|
|
77
|
+
* });
|
|
78
|
+
* };
|
|
79
|
+
*
|
|
80
|
+
* return <FileUploader onUpload={handleUpload} />;
|
|
81
|
+
* }
|
|
82
|
+
*
|
|
83
|
+
* // Advanced: Multiple clients with different configurations
|
|
84
|
+
* function MultiClientComponent() {
|
|
85
|
+
* // Client for image uploads
|
|
86
|
+
* const imageClient = useUploadistaClient({
|
|
87
|
+
* baseUrl: 'https://images.example.com',
|
|
88
|
+
* storageId: 'images',
|
|
89
|
+
* chunkSize: 2 * 1024 * 1024, // 2MB for images
|
|
90
|
+
* });
|
|
91
|
+
*
|
|
92
|
+
* // Client for document uploads
|
|
93
|
+
* const docClient = useUploadistaClient({
|
|
94
|
+
* baseUrl: 'https://docs.example.com',
|
|
95
|
+
* storageId: 'documents',
|
|
96
|
+
* chunkSize: 512 * 1024, // 512KB for documents
|
|
97
|
+
* });
|
|
98
|
+
*
|
|
99
|
+
* return (
|
|
100
|
+
* <div>
|
|
101
|
+
* <ImageUploader client={imageClient.client} />
|
|
102
|
+
* <DocumentUploader client={docClient.client} />
|
|
103
|
+
* </div>
|
|
104
|
+
* );
|
|
105
|
+
* }
|
|
106
|
+
* ```
|
|
107
|
+
*
|
|
108
|
+
* @see {@link UploadistaProvider} for the recommended way to provide client context
|
|
109
|
+
*/
|
|
110
|
+
export function useUploadistaClient(
|
|
111
|
+
options: UseUploadistaClientOptions,
|
|
112
|
+
): UseUploadistaClientReturn {
|
|
113
|
+
// Store the options in a ref to enable stable dependency checking
|
|
114
|
+
const optionsRef = useRef<UseUploadistaClientOptions>(options);
|
|
115
|
+
|
|
116
|
+
// Update ref on each render but only create new client when essential deps change
|
|
117
|
+
optionsRef.current = options;
|
|
118
|
+
|
|
119
|
+
// Create client instance with stable identity
|
|
120
|
+
const client = useMemo(() => {
|
|
121
|
+
return createUploadistaClient({
|
|
122
|
+
baseUrl: options.baseUrl,
|
|
123
|
+
storageId: options.storageId,
|
|
124
|
+
uploadistaBasePath: options.uploadistaBasePath,
|
|
125
|
+
chunkSize: options.chunkSize,
|
|
126
|
+
storeFingerprintForResuming: options.storeFingerprintForResuming,
|
|
127
|
+
retryDelays: options.retryDelays,
|
|
128
|
+
parallelUploads: options.parallelUploads,
|
|
129
|
+
parallelChunkSize: options.parallelChunkSize,
|
|
130
|
+
uploadStrategy: options.uploadStrategy,
|
|
131
|
+
smartChunking: options.smartChunking,
|
|
132
|
+
networkMonitoring: options.networkMonitoring,
|
|
133
|
+
uploadMetrics: options.uploadMetrics,
|
|
134
|
+
connectionPooling: options.connectionPooling,
|
|
135
|
+
// logger: options.logger,
|
|
136
|
+
auth: options.auth,
|
|
137
|
+
onEvent: options.onEvent,
|
|
138
|
+
});
|
|
139
|
+
}, [options]);
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
client,
|
|
143
|
+
config: options,
|
|
144
|
+
};
|
|
145
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Flow Upload Hooks
|
|
2
|
+
|
|
3
|
+
export type {
|
|
4
|
+
FlowUploadListProps,
|
|
5
|
+
FlowUploadListRenderProps,
|
|
6
|
+
SimpleFlowUploadListItemProps,
|
|
7
|
+
SimpleFlowUploadListProps,
|
|
8
|
+
} from "./components/flow-upload-list";
|
|
9
|
+
export {
|
|
10
|
+
FlowUploadList,
|
|
11
|
+
SimpleFlowUploadList,
|
|
12
|
+
SimpleFlowUploadListItem,
|
|
13
|
+
} from "./components/flow-upload-list";
|
|
14
|
+
// Flow Upload Components
|
|
15
|
+
export type {
|
|
16
|
+
FlowUploadZoneProps,
|
|
17
|
+
FlowUploadZoneRenderProps,
|
|
18
|
+
SimpleFlowUploadZoneProps,
|
|
19
|
+
} from "./components/flow-upload-zone";
|
|
20
|
+
export {
|
|
21
|
+
FlowUploadZone,
|
|
22
|
+
SimpleFlowUploadZone,
|
|
23
|
+
} from "./components/flow-upload-zone";
|
|
24
|
+
export type {
|
|
25
|
+
FlowUploadState,
|
|
26
|
+
FlowUploadStatus,
|
|
27
|
+
UseFlowUploadReturn,
|
|
28
|
+
} from "./hooks/use-flow-upload";
|
|
29
|
+
export { useFlowUpload } from "./hooks/use-flow-upload";
|
|
30
|
+
export type { UseMultiFlowUploadReturn } from "./hooks/use-multi-flow-upload";
|
|
31
|
+
export { useMultiFlowUpload } from "./hooks/use-multi-flow-upload";
|
|
32
|
+
|
|
33
|
+
// Flow Hooks
|
|
34
|
+
|
|
35
|
+
// Upload Hooks
|
|
36
|
+
export type {
|
|
37
|
+
SimpleUploadListItemProps,
|
|
38
|
+
UploadListProps,
|
|
39
|
+
UploadListRenderProps,
|
|
40
|
+
} from "./components/upload-list";
|
|
41
|
+
export { SimpleUploadListItem, UploadList } from "./components/upload-list";
|
|
42
|
+
export type {
|
|
43
|
+
SimpleUploadZoneProps,
|
|
44
|
+
UploadZoneProps,
|
|
45
|
+
UploadZoneRenderProps,
|
|
46
|
+
} from "./components/upload-zone";
|
|
47
|
+
export { SimpleUploadZone, UploadZone } from "./components/upload-zone";
|
|
48
|
+
|
|
49
|
+
// Components
|
|
50
|
+
export {
|
|
51
|
+
UploadistaProvider,
|
|
52
|
+
useUploadistaContext,
|
|
53
|
+
} from "./components/uploadista-provider";
|
|
54
|
+
export type {
|
|
55
|
+
DragDropOptions,
|
|
56
|
+
DragDropState,
|
|
57
|
+
UseDragDropReturn,
|
|
58
|
+
} from "./hooks/use-drag-drop";
|
|
59
|
+
export { useDragDrop } from "./hooks/use-drag-drop";
|
|
60
|
+
|
|
61
|
+
export type {
|
|
62
|
+
MultiUploadOptions,
|
|
63
|
+
MultiUploadState,
|
|
64
|
+
UploadItem,
|
|
65
|
+
UseMultiUploadReturn,
|
|
66
|
+
} from "./hooks/use-multi-upload";
|
|
67
|
+
export { useMultiUpload } from "./hooks/use-multi-upload";
|
|
68
|
+
export type {
|
|
69
|
+
UploadState,
|
|
70
|
+
UploadStatus,
|
|
71
|
+
UseUploadOptions,
|
|
72
|
+
UseUploadReturn,
|
|
73
|
+
} from "./hooks/use-upload";
|
|
74
|
+
export { useUpload } from "./hooks/use-upload";
|
|
75
|
+
export type {
|
|
76
|
+
FileUploadMetrics,
|
|
77
|
+
UploadMetrics,
|
|
78
|
+
UseUploadMetricsOptions,
|
|
79
|
+
UseUploadMetricsReturn,
|
|
80
|
+
} from "./hooks/use-upload-metrics";
|
|
81
|
+
export { useUploadMetrics } from "./hooks/use-upload-metrics";
|
|
82
|
+
// Types - Hooks
|
|
83
|
+
export type {
|
|
84
|
+
UseUploadistaClientOptions,
|
|
85
|
+
UseUploadistaClientReturn,
|
|
86
|
+
} from "./hooks/use-uploadista-client";
|
|
87
|
+
export { useUploadistaClient } from "./hooks/use-uploadista-client";
|