@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/README.md ADDED
@@ -0,0 +1,318 @@
1
+ # @uploadista/react
2
+
3
+ React hooks and components for the Uploadista unified client. Provides a complete solution for file uploads and flow execution with WebSocket support, progress tracking, and comprehensive state management.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @uploadista/react @uploadista/client @uploadista/core
9
+ ```
10
+
11
+ ## Features
12
+
13
+ - **Upload Management**: Single and multi-file upload with progress tracking
14
+ - **Flow Execution**: Execute processing flows with real-time WebSocket updates
15
+ - **Drag & Drop**: Built-in drag-and-drop support with file validation
16
+ - **State Management**: Comprehensive state management for uploads and flows
17
+ - **Performance Metrics**: Track upload performance, speed, and network conditions
18
+ - **TypeScript**: Full TypeScript support with type inference
19
+
20
+ ## Quick Start
21
+
22
+ ### Upload Provider Setup
23
+
24
+ Wrap your app with the `UploadProvider` to provide upload client configuration:
25
+
26
+ ```tsx
27
+ import { UploadProvider } from '@uploadista/react';
28
+
29
+ function App() {
30
+ return (
31
+ <UploadProvider
32
+ baseUrl="https://api.example.com"
33
+ storageId="my-storage"
34
+ chunkSize={1024 * 1024} // 1MB chunks
35
+ storeFingerprintForResuming={true}
36
+ onEvent={(event) => {
37
+ console.log('Upload event:', event);
38
+ }}
39
+ >
40
+ <YourApp />
41
+ </UploadProvider>
42
+ );
43
+ }
44
+ ```
45
+
46
+ ### Single File Upload
47
+
48
+ ```tsx
49
+ import { useUploadContext, useUpload } from '@uploadista/react';
50
+
51
+ function SingleFileUploader() {
52
+ const uploadClient = useUploadContext();
53
+ const upload = useUpload(uploadClient, {
54
+ onSuccess: (result) => console.log('Upload complete:', result),
55
+ onError: (error) => console.error('Upload failed:', error),
56
+ onProgress: (progress) => console.log('Progress:', progress + '%'),
57
+ });
58
+
59
+ const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
60
+ const file = e.target.files?.[0];
61
+ if (file) upload.upload(file);
62
+ };
63
+
64
+ return (
65
+ <div>
66
+ <input type="file" onChange={handleFileSelect} />
67
+ {upload.isUploading && <div>Progress: {upload.state.progress}%</div>}
68
+ {upload.state.error && <div>Error: {upload.state.error.message}</div>}
69
+ {upload.canRetry && <button onClick={upload.retry}>Retry</button>}
70
+ <button onClick={upload.abort} disabled={!upload.isUploading}>Abort</button>
71
+ </div>
72
+ );
73
+ }
74
+ ```
75
+
76
+ ### Multi-File Upload
77
+
78
+ ```tsx
79
+ import { useUploadContext, useMultiUpload } from '@uploadista/react';
80
+
81
+ function MultiFileUploader() {
82
+ const uploadClient = useUploadContext();
83
+ const multiUpload = useMultiUpload(uploadClient, {
84
+ maxConcurrent: 3,
85
+ onComplete: (results) => {
86
+ console.log(`${results.successful.length}/${results.total} successful`);
87
+ },
88
+ });
89
+
90
+ const handleFilesSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
91
+ if (e.target.files) {
92
+ multiUpload.addFiles(Array.from(e.target.files));
93
+ multiUpload.startAll();
94
+ }
95
+ };
96
+
97
+ return (
98
+ <div>
99
+ <input type="file" multiple onChange={handleFilesSelect} />
100
+ <div>Progress: {multiUpload.state.progress}%</div>
101
+ <div>
102
+ {multiUpload.state.uploading} uploading,
103
+ {multiUpload.state.successful} successful,
104
+ {multiUpload.state.failed} failed
105
+ </div>
106
+
107
+ {multiUpload.items.map((item) => (
108
+ <div key={item.id}>
109
+ {item.file.name}: {item.state.status} ({item.state.progress}%)
110
+ </div>
111
+ ))}
112
+ </div>
113
+ );
114
+ }
115
+ ```
116
+
117
+ ### Drag & Drop Upload
118
+
119
+ ```tsx
120
+ import { useUploadContext, useDragDrop, useMultiUpload } from '@uploadista/react';
121
+
122
+ function DragDropUploader() {
123
+ const uploadClient = useUploadContext();
124
+ const multiUpload = useMultiUpload(uploadClient);
125
+
126
+ const dragDrop = useDragDrop({
127
+ accept: ['image/*', '.pdf'],
128
+ maxFiles: 5,
129
+ maxFileSize: 10 * 1024 * 1024, // 10MB
130
+ onFilesReceived: (files) => {
131
+ multiUpload.addFiles(files);
132
+ multiUpload.startAll();
133
+ },
134
+ onValidationError: (errors) => {
135
+ console.error('Validation errors:', errors);
136
+ },
137
+ });
138
+
139
+ return (
140
+ <div
141
+ {...dragDrop.dragHandlers}
142
+ style={{
143
+ border: dragDrop.state.isDragging ? '2px dashed #007bff' : '2px dashed #ccc',
144
+ padding: '2rem',
145
+ textAlign: 'center',
146
+ }}
147
+ onClick={dragDrop.openFilePicker}
148
+ >
149
+ {dragDrop.state.isDragging ? (
150
+ <p>Drop files here...</p>
151
+ ) : (
152
+ <p>Drag files here or click to select</p>
153
+ )}
154
+
155
+ {dragDrop.state.errors.length > 0 && (
156
+ <div>
157
+ {dragDrop.state.errors.map((error, i) => (
158
+ <p key={i} style={{ color: 'red' }}>{error}</p>
159
+ ))}
160
+ </div>
161
+ )}
162
+
163
+ <input {...dragDrop.inputProps} />
164
+ </div>
165
+ );
166
+ }
167
+ ```
168
+
169
+ ### Upload Zone (Combined Drag & Drop + Upload)
170
+
171
+ ```tsx
172
+ import { SimpleUploadZone } from '@uploadista/react';
173
+
174
+ function SimpleUploader() {
175
+ return (
176
+ <SimpleUploadZone
177
+ multiple={true}
178
+ accept={['image/*']}
179
+ maxFileSize={5 * 1024 * 1024}
180
+ onUploadStart={(files) => console.log('Starting uploads:', files.length)}
181
+ onValidationError={(errors) => console.error('Validation errors:', errors)}
182
+ multiUploadOptions={{
183
+ maxConcurrent: 3,
184
+ onComplete: (results) => console.log('All uploads complete:', results),
185
+ }}
186
+ />
187
+ );
188
+ }
189
+ ```
190
+
191
+ ### Flow Execution
192
+
193
+ ```tsx
194
+ import { useFlowClient, useFlow } from '@uploadista/react';
195
+
196
+ function FlowExecutor() {
197
+ const flowClient = useFlowClient({
198
+ baseUrl: 'https://api.example.com',
199
+ storageId: 'my-storage',
200
+ chunkSize: 1024 * 1024,
201
+ storeFingerprintForResuming: true,
202
+ onEvent: (event) => console.log('Flow event:', event),
203
+ });
204
+
205
+ const flow = useFlow(flowClient, {
206
+ flowId: 'image-processing',
207
+ storageId: 'my-storage',
208
+ autoConnectWebSocket: true,
209
+ onSuccess: (result) => console.log('Flow completed:', result),
210
+ onError: (error) => console.error('Flow failed:', error),
211
+ });
212
+
213
+ const handleExecute = () => {
214
+ flow.executeFlow({
215
+ image: 'photo.jpg',
216
+ quality: 80,
217
+ });
218
+ };
219
+
220
+ return (
221
+ <div>
222
+ <button onClick={handleExecute} disabled={flow.state.status === 'running'}>
223
+ Execute Flow
224
+ </button>
225
+
226
+ {flow.state.status === 'running' && <div>Processing...</div>}
227
+ {flow.state.status === 'success' && <div>Success!</div>}
228
+ {flow.state.error && <div>Error: {flow.state.error.message}</div>}
229
+ </div>
230
+ );
231
+ }
232
+ ```
233
+
234
+ ### Upload Metrics
235
+
236
+ ```tsx
237
+ import { useUploadMetrics } from '@uploadista/react';
238
+
239
+ function UploadMetricsDisplay() {
240
+ const metrics = useUploadMetrics({
241
+ speedCalculationInterval: 1000,
242
+ onMetricsUpdate: (metrics) => {
243
+ console.log(`Speed: ${metrics.currentSpeed / 1024} KB/s`);
244
+ },
245
+ });
246
+
247
+ // Track file uploads
248
+ React.useEffect(() => {
249
+ // When starting an upload
250
+ metrics.startFileUpload('file-1', 'photo.jpg', 1024 * 1024);
251
+
252
+ // When progress updates
253
+ metrics.updateFileProgress('file-1', 512 * 1024);
254
+
255
+ // When upload completes
256
+ metrics.completeFileUpload('file-1');
257
+ }, []);
258
+
259
+ return (
260
+ <div>
261
+ <div>Overall Progress: {metrics.metrics.progress}%</div>
262
+ <div>Speed: {(metrics.metrics.currentSpeed / 1024).toFixed(1)} KB/s</div>
263
+ <div>Files: {metrics.metrics.completedFiles}/{metrics.metrics.totalFiles}</div>
264
+
265
+ {metrics.fileMetrics.map((file) => (
266
+ <div key={file.id}>
267
+ {file.filename}: {file.progress}%
268
+ </div>
269
+ ))}
270
+ </div>
271
+ );
272
+ }
273
+ ```
274
+
275
+ ## API Reference
276
+
277
+ ### Hooks
278
+
279
+ #### Upload Hooks
280
+ - `useUploadClient(options)` - Create a unified upload/flow client
281
+ - `useUpload(client, options)` - Manage single file upload
282
+ - `useMultiUpload(client, options)` - Manage multiple file uploads
283
+ - `useUploadMetrics(options)` - Track upload performance metrics
284
+
285
+ #### Flow Hooks
286
+ - `useUploadFlow(client, options)` - Execute and manage flows
287
+
288
+ #### UI Hooks
289
+ - `useDragDrop(options)` - Drag and drop functionality
290
+ - `useUploadContext()` - Access upload client from context
291
+
292
+ ### Components
293
+
294
+ #### Providers
295
+ - `<UploadProvider>` - Context provider for upload client
296
+
297
+ #### Upload Components
298
+ - `<UploadZone>` - Headless upload zone with render props
299
+ - `<SimpleUploadZone>` - Pre-styled upload zone
300
+ - `<UploadList>` - Headless upload list with render props
301
+ - `<SimpleUploadListItem>` - Pre-styled upload list item
302
+
303
+ ### Utilities
304
+
305
+ - `formatFileSize(bytes)` - Format bytes to human-readable size
306
+ - `formatSpeed(bytesPerSecond)` - Format speed to human-readable format
307
+ - `formatDuration(milliseconds)` - Format duration to human-readable format
308
+ - `validateFileType(file, accept)` - Validate file against accepted types
309
+ - `isImageFile(file)` - Check if file is an image
310
+ - `isVideoFile(file)` - Check if file is a video
311
+ - `isAudioFile(file)` - Check if file is audio
312
+ - `isDocumentFile(file)` - Check if file is a document
313
+ - `createFilePreview(file)` - Create preview URL for file
314
+ - `revokeFilePreview(url)` - Clean up preview URL
315
+
316
+ ## License
317
+
318
+ MIT
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@uploadista/react",
3
+ "type": "module",
4
+ "version": "0.0.3",
5
+ "description": "React client for Uploadista",
6
+ "license": "MIT",
7
+ "author": "Uploadista",
8
+ "exports": {
9
+ ".": "./src/index.ts",
10
+ "./components/*": "./src/components/*.tsx",
11
+ "./hooks/*": "./src/hooks/*.ts",
12
+ "./utils/*": "./src/utils/*.ts"
13
+ },
14
+ "dependencies": {
15
+ "react": "19.2.0",
16
+ "react-dom": "19.2.0",
17
+ "@uploadista/client-core": "0.0.3",
18
+ "@uploadista/core": "0.0.3",
19
+ "@uploadista/client-browser": "0.0.3"
20
+ },
21
+ "devDependencies": {
22
+ "@types/react": "19.2.2",
23
+ "@types/react-dom": "19.2.2",
24
+ "vitest": "3.2.4",
25
+ "@uploadista/typescript-config": "0.0.3"
26
+ },
27
+ "scripts": {
28
+ "format": "biome format --write ./src",
29
+ "lint": "biome lint --write ./src",
30
+ "check": "biome check --write ./src",
31
+ "test": "vitest",
32
+ "test:run": "vitest run",
33
+ "test:watch": "vitest --watch"
34
+ }
35
+ }