@uploadista/react 0.0.17-beta.4 → 0.0.17-beta.6

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.
Files changed (37) hide show
  1. package/dist/components/index.d.mts +3 -3
  2. package/dist/components/index.mjs +1 -1
  3. package/dist/hooks/index.d.mts +3 -3
  4. package/dist/hooks/index.mjs +1 -1
  5. package/dist/index.d.mts +6 -6
  6. package/dist/index.d.mts.map +1 -1
  7. package/dist/index.mjs +1 -1
  8. package/dist/upload-zone-BPIAbcsx.mjs +6 -0
  9. package/dist/upload-zone-BPIAbcsx.mjs.map +1 -0
  10. package/dist/{uploadista-provider-DIMEpwsu.d.mts → uploadista-provider-bZlGf-uJ.d.mts} +62 -15
  11. package/dist/uploadista-provider-bZlGf-uJ.d.mts.map +1 -0
  12. package/dist/use-upload-BpnD7FA-.mjs +2 -0
  13. package/dist/use-upload-BpnD7FA-.mjs.map +1 -0
  14. package/dist/use-upload-metrics-BoGtFTrl.mjs +2 -0
  15. package/dist/use-upload-metrics-BoGtFTrl.mjs.map +1 -0
  16. package/dist/{use-upload-metrics-R1xNz6Aa.d.mts → use-upload-metrics-DhzS4lhG.d.mts} +207 -5
  17. package/dist/use-upload-metrics-DhzS4lhG.d.mts.map +1 -0
  18. package/dist/{use-uploadista-client-ty1ffKD7.d.mts → use-uploadista-client-CfpEI3Us.d.mts} +228 -3
  19. package/dist/use-uploadista-client-CfpEI3Us.d.mts.map +1 -0
  20. package/package.json +5 -5
  21. package/src/components/flow-input.tsx +298 -0
  22. package/src/components/index.tsx +3 -0
  23. package/src/contexts/flow-manager-context.tsx +1 -0
  24. package/src/hooks/index.ts +20 -6
  25. package/src/hooks/use-flow-execution.ts +505 -0
  26. package/src/hooks/use-flow-upload.ts +23 -0
  27. package/src/hooks/use-flow.ts +439 -0
  28. package/src/index.ts +15 -0
  29. package/dist/upload-zone-DN7Gem65.mjs +0 -2
  30. package/dist/upload-zone-DN7Gem65.mjs.map +0 -1
  31. package/dist/uploadista-provider-DIMEpwsu.d.mts.map +0 -1
  32. package/dist/use-upload-C7QZSt1M.mjs +0 -2
  33. package/dist/use-upload-C7QZSt1M.mjs.map +0 -1
  34. package/dist/use-upload-metrics-DEaujDeM.mjs +0 -2
  35. package/dist/use-upload-metrics-DEaujDeM.mjs.map +0 -1
  36. package/dist/use-upload-metrics-R1xNz6Aa.d.mts.map +0 -1
  37. package/dist/use-uploadista-client-ty1ffKD7.d.mts.map +0 -1
@@ -0,0 +1,439 @@
1
+ import type { FlowUploadOptions } from "@uploadista/client-browser";
2
+ import type {
3
+ FlowManager,
4
+ FlowUploadState,
5
+ FlowUploadStatus,
6
+ InputExecutionState,
7
+ } from "@uploadista/client-core";
8
+ import type { Flow, TypedOutput } from "@uploadista/core/flow";
9
+ import { useCallback, useEffect, useRef, useState } from "react";
10
+ import { useUploadistaContext } from "../components/uploadista-provider";
11
+ import { useFlowManagerContext } from "../contexts/flow-manager-context";
12
+
13
+ // Re-export types from core for convenience
14
+ export type { FlowUploadState, FlowUploadStatus, InputExecutionState };
15
+
16
+ /**
17
+ * Input metadata discovered from the flow
18
+ */
19
+ export interface FlowInputMetadata {
20
+ /** Input node ID */
21
+ nodeId: string;
22
+ /** Human-readable node name */
23
+ nodeName: string;
24
+ /** Node description explaining what input is needed */
25
+ nodeDescription: string;
26
+ /** Input node type */
27
+ nodeType: string;
28
+ /** Whether this input is required */
29
+ required: boolean;
30
+ }
31
+
32
+ /**
33
+ * Return value from the useFlow hook with upload control methods and state.
34
+ *
35
+ * @property state - Complete flow upload state with progress and outputs
36
+ * @property inputMetadata - Metadata about discovered input nodes (null until discovered)
37
+ * @property inputStates - Per-input execution state for multi-input flows
38
+ * @property inputs - Current input values set via setInput()
39
+ * @property setInput - Set an input value for a specific node (for progressive provision)
40
+ * @property execute - Execute the flow with current inputs (auto-detects types)
41
+ * @property upload - Convenience method for single-file upload (same as execute with one file input)
42
+ * @property abort - Cancel the current upload and flow execution
43
+ * @property pause - Pause the current upload
44
+ * @property reset - Reset state to idle (clears all data)
45
+ * @property isUploading - True when upload or processing is active
46
+ * @property isUploadingFile - True only during file upload phase
47
+ * @property isProcessing - True only during flow processing phase
48
+ * @property isDiscoveringInputs - True while discovering flow inputs
49
+ */
50
+ export interface UseFlowReturn {
51
+ /**
52
+ * Current upload state
53
+ */
54
+ state: FlowUploadState;
55
+
56
+ /**
57
+ * Discovered input nodes metadata (null until discovery completes)
58
+ */
59
+ inputMetadata: FlowInputMetadata[] | null;
60
+
61
+ /**
62
+ * Per-input execution state for multi-input flows
63
+ */
64
+ inputStates: ReadonlyMap<string, InputExecutionState>;
65
+
66
+ /**
67
+ * Current inputs set via setInput()
68
+ */
69
+ inputs: Record<string, unknown>;
70
+
71
+ /**
72
+ * Set an input value for a specific node.
73
+ * For progressive input provision before calling execute().
74
+ *
75
+ * @param nodeId - The input node ID
76
+ * @param value - The input value (File, URL string, or structured data)
77
+ */
78
+ setInput: (nodeId: string, value: unknown) => void;
79
+
80
+ /**
81
+ * Execute the flow with current inputs.
82
+ * Automatically detects input types and routes appropriately.
83
+ * For single input, uses standard upload path.
84
+ * For multiple inputs, requires multiInputUploadFn.
85
+ */
86
+ execute: () => Promise<void>;
87
+
88
+ /**
89
+ * Upload a single file through the flow (convenience method).
90
+ * Equivalent to setInput(firstNodeId, file) + execute().
91
+ *
92
+ * @param file - File or Blob to upload
93
+ */
94
+ upload: (file: File | Blob) => Promise<void>;
95
+
96
+ /**
97
+ * Abort the current upload
98
+ */
99
+ abort: () => void;
100
+
101
+ /**
102
+ * Pause the current upload
103
+ */
104
+ pause: () => void;
105
+
106
+ /**
107
+ * Reset the upload state and clear all inputs
108
+ */
109
+ reset: () => void;
110
+
111
+ /**
112
+ * Whether an upload or flow execution is in progress (uploading OR processing)
113
+ */
114
+ isUploading: boolean;
115
+
116
+ /**
117
+ * Whether the file is currently being uploaded (chunks being sent)
118
+ */
119
+ isUploadingFile: boolean;
120
+
121
+ /**
122
+ * Whether the flow is currently processing (after upload completes)
123
+ */
124
+ isProcessing: boolean;
125
+
126
+ /**
127
+ * Whether the hook is discovering flow inputs
128
+ */
129
+ isDiscoveringInputs: boolean;
130
+ }
131
+
132
+ const initialState: FlowUploadState = {
133
+ status: "idle",
134
+ progress: 0,
135
+ bytesUploaded: 0,
136
+ totalBytes: null,
137
+ error: null,
138
+ jobId: null,
139
+ flowStarted: false,
140
+ currentNodeName: null,
141
+ currentNodeType: null,
142
+ flowOutputs: null,
143
+ };
144
+
145
+ /**
146
+ * React hook for executing flows with single or multiple inputs.
147
+ * Automatically discovers input nodes and detects input types (File, URL, structured data).
148
+ * Supports progressive input provision via setInput() and execute().
149
+ *
150
+ * This is the unified flow hook that replaces useFlowUpload for advanced use cases.
151
+ * It provides:
152
+ * - Auto-discovery of flow input nodes
153
+ * - Automatic input type detection (file → upload, string → URL, object → data)
154
+ * - Progressive input provision via setInput()
155
+ * - Multi-input support with parallel coordination
156
+ * - Per-input state tracking
157
+ *
158
+ * Must be used within FlowManagerProvider (which must be within UploadistaProvider).
159
+ * Flow events are automatically routed by the provider to the appropriate manager.
160
+ *
161
+ * @param options - Flow upload configuration including flow ID and event handlers
162
+ * @returns Flow upload state and control methods
163
+ *
164
+ * @example
165
+ * ```tsx
166
+ * // Single file upload (simple case)
167
+ * function SingleFileUploader() {
168
+ * const flow = useFlow({
169
+ * flowConfig: {
170
+ * flowId: "image-optimization",
171
+ * storageId: "s3-images",
172
+ * },
173
+ * onSuccess: (outputs) => {
174
+ * console.log("Flow outputs:", outputs);
175
+ * },
176
+ * });
177
+ *
178
+ * return (
179
+ * <div>
180
+ * <input
181
+ * type="file"
182
+ * onChange={(e) => {
183
+ * const file = e.target.files?.[0];
184
+ * if (file) flow.upload(file);
185
+ * }}
186
+ * />
187
+ * {flow.isUploading && <div>Progress: {flow.state.progress}%</div>}
188
+ * </div>
189
+ * );
190
+ * }
191
+ *
192
+ * // Multi-input with progressive provision
193
+ * function MultiInputFlow() {
194
+ * const flow = useFlow({
195
+ * flowConfig: {
196
+ * flowId: "multi-source-processing",
197
+ * storageId: "default",
198
+ * },
199
+ * });
200
+ *
201
+ * return (
202
+ * <div>
203
+ * {flow.inputMetadata?.map((input) => (
204
+ * <div key={input.nodeId}>
205
+ * <label>{input.nodeId}</label>
206
+ * {input.nodeType === "streaming-input-v1" ? (
207
+ * <input
208
+ * type="file"
209
+ * onChange={(e) => {
210
+ * const file = e.target.files?.[0];
211
+ * if (file) flow.setInput(input.nodeId, file);
212
+ * }}
213
+ * />
214
+ * ) : (
215
+ * <input
216
+ * type="url"
217
+ * onChange={(e) => flow.setInput(input.nodeId, e.target.value)}
218
+ * />
219
+ * )}
220
+ * </div>
221
+ * ))}
222
+ * <button onClick={flow.execute} disabled={flow.isUploading}>
223
+ * Execute Flow
224
+ * </button>
225
+ *
226
+ * {flow.isUploading && (
227
+ * <div>
228
+ * {Array.from(flow.inputStates.values()).map((inputState) => (
229
+ * <div key={inputState.nodeId}>
230
+ * {inputState.nodeId}: {inputState.status} ({inputState.progress}%)
231
+ * </div>
232
+ * ))}
233
+ * </div>
234
+ * )}
235
+ * </div>
236
+ * );
237
+ * }
238
+ * ```
239
+ *
240
+ * @see {@link useFlowUpload} for a simpler file-only upload hook
241
+ */
242
+ export function useFlow(options: FlowUploadOptions): UseFlowReturn {
243
+ const { client } = useUploadistaContext();
244
+ const { getManager, releaseManager } = useFlowManagerContext();
245
+ const [state, setState] = useState<FlowUploadState>(initialState);
246
+ const [inputMetadata, setInputMetadata] = useState<
247
+ FlowInputMetadata[] | null
248
+ >(null);
249
+ const [isDiscoveringInputs, setIsDiscoveringInputs] = useState(false);
250
+ const [inputs, setInputs] = useState<Record<string, unknown>>({});
251
+ const [inputStates, setInputStates] = useState<
252
+ ReadonlyMap<string, InputExecutionState>
253
+ >(new Map());
254
+ const managerRef = useRef<FlowManager<unknown> | null>(null);
255
+
256
+ // Store callbacks in refs so they can be updated without recreating the manager
257
+ const callbacksRef = useRef(options);
258
+
259
+ // Update refs on every render to capture latest callbacks
260
+ useEffect(() => {
261
+ callbacksRef.current = options;
262
+ });
263
+
264
+ // Auto-discover flow inputs on mount
265
+ useEffect(() => {
266
+ const discoverInputs = async () => {
267
+ setIsDiscoveringInputs(true);
268
+ try {
269
+ const { flow } = await client.getFlow(options.flowConfig.flowId);
270
+
271
+ // Find all input nodes
272
+ const inputNodes = flow.nodes.filter((node) => node.type === "input");
273
+
274
+ const metadata: FlowInputMetadata[] = inputNodes.map((node) => ({
275
+ nodeId: node.id,
276
+ nodeName: node.name,
277
+ nodeDescription: node.description,
278
+ nodeType: node.nodeType,
279
+ // TODO: Add required field to node schema to determine if input is required
280
+ required: true,
281
+ }));
282
+
283
+ setInputMetadata(metadata);
284
+ } catch (error) {
285
+ console.error("Failed to discover flow inputs:", error);
286
+ } finally {
287
+ setIsDiscoveringInputs(false);
288
+ }
289
+ };
290
+
291
+ discoverInputs();
292
+ }, [client, options.flowConfig.flowId]);
293
+
294
+ // Get or create manager from context when component mounts
295
+ useEffect(() => {
296
+ const flowId = options.flowConfig.flowId;
297
+
298
+ // Create stable callback wrappers that call the latest callbacks via refs
299
+ const stableCallbacks = {
300
+ onStateChange: (newState: FlowUploadState) => {
301
+ setState(newState);
302
+ },
303
+ onProgress: (
304
+ uploadId: string,
305
+ bytesUploaded: number,
306
+ totalBytes: number | null,
307
+ ) => {
308
+ callbacksRef.current.onProgress?.(uploadId, bytesUploaded, totalBytes);
309
+ },
310
+ onChunkComplete: (
311
+ chunkSize: number,
312
+ bytesAccepted: number,
313
+ bytesTotal: number | null,
314
+ ) => {
315
+ callbacksRef.current.onChunkComplete?.(
316
+ chunkSize,
317
+ bytesAccepted,
318
+ bytesTotal,
319
+ );
320
+ },
321
+ onFlowComplete: (outputs: TypedOutput[]) => {
322
+ callbacksRef.current.onFlowComplete?.(outputs);
323
+ },
324
+ onSuccess: (outputs: TypedOutput[]) => {
325
+ callbacksRef.current.onSuccess?.(outputs);
326
+ },
327
+ onError: (error: Error) => {
328
+ callbacksRef.current.onError?.(error);
329
+ },
330
+ onAbort: () => {
331
+ callbacksRef.current.onAbort?.();
332
+ },
333
+ };
334
+
335
+ // Get manager from context (creates if doesn't exist, increments ref count)
336
+ managerRef.current = getManager(flowId, stableCallbacks, options);
337
+
338
+ // Set up interval to poll input states for multi-input flows
339
+ const pollInterval = setInterval(() => {
340
+ if (managerRef.current) {
341
+ const states = managerRef.current.getInputStates();
342
+ if (states.size > 0) {
343
+ setInputStates(new Map(states));
344
+ }
345
+ }
346
+ }, 100); // Poll every 100ms
347
+
348
+ // Release manager when component unmounts or flowId changes
349
+ return () => {
350
+ clearInterval(pollInterval);
351
+ releaseManager(flowId);
352
+ managerRef.current = null;
353
+ };
354
+ }, [
355
+ options.flowConfig.flowId,
356
+ options.flowConfig.storageId,
357
+ options.flowConfig.outputNodeId,
358
+ getManager,
359
+ releaseManager,
360
+ ]);
361
+
362
+ // Set an input value
363
+ const setInput = useCallback((nodeId: string, value: unknown) => {
364
+ setInputs((prev) => ({ ...prev, [nodeId]: value }));
365
+ }, []);
366
+
367
+ // Execute flow with current inputs
368
+ const execute = useCallback(async () => {
369
+ if (!managerRef.current) {
370
+ throw new Error("FlowManager not initialized");
371
+ }
372
+
373
+ if (Object.keys(inputs).length === 0) {
374
+ throw new Error(
375
+ "No inputs provided. Use setInput() to provide inputs before calling execute()",
376
+ );
377
+ }
378
+
379
+ await managerRef.current.executeFlow(inputs);
380
+ }, [inputs]);
381
+
382
+ // Convenience method for single file upload
383
+ const upload = useCallback(
384
+ async (file: File | Blob) => {
385
+ if (!managerRef.current) {
386
+ throw new Error("FlowManager not initialized");
387
+ }
388
+
389
+ // If we have input metadata, use the first input node
390
+ // Otherwise, let the manager discover it
391
+ if (inputMetadata && inputMetadata.length > 0) {
392
+ const firstInputNode = inputMetadata[0];
393
+ setInputs({ [firstInputNode.nodeId]: file });
394
+ await managerRef.current.executeFlow({ [firstInputNode.nodeId]: file });
395
+ } else {
396
+ // Fall back to direct upload (manager will handle discovery)
397
+ await managerRef.current.upload(file);
398
+ }
399
+ },
400
+ [inputMetadata],
401
+ );
402
+
403
+ const abort = useCallback(() => {
404
+ managerRef.current?.abort();
405
+ }, []);
406
+
407
+ const pause = useCallback(() => {
408
+ managerRef.current?.pause();
409
+ }, []);
410
+
411
+ const reset = useCallback(() => {
412
+ managerRef.current?.reset();
413
+ setInputs({});
414
+ setInputStates(new Map());
415
+ }, []);
416
+
417
+ // Derive computed values from state (reactive to state changes)
418
+ const isUploading =
419
+ state.status === "uploading" || state.status === "processing";
420
+ const isUploadingFile = state.status === "uploading";
421
+ const isProcessing = state.status === "processing";
422
+
423
+ return {
424
+ state,
425
+ inputMetadata,
426
+ inputStates,
427
+ inputs,
428
+ setInput,
429
+ execute,
430
+ upload,
431
+ abort,
432
+ pause,
433
+ reset,
434
+ isUploading,
435
+ isUploadingFile,
436
+ isProcessing,
437
+ isDiscoveringInputs,
438
+ };
439
+ }
package/src/index.ts CHANGED
@@ -15,6 +15,8 @@ export type {
15
15
  export { useUploadEvents } from "./hooks/use-upload-events";
16
16
 
17
17
  // Flow Upload Hooks
18
+ export type { FlowInputProps } from "./components/flow-input";
19
+ export { FlowInput } from "./components/flow-input";
18
20
 
19
21
  export type {
20
22
  FlowUploadListProps,
@@ -47,6 +49,19 @@ export type { UseMultiFlowUploadReturn } from "./hooks/use-multi-flow-upload";
47
49
  export { useMultiFlowUpload } from "./hooks/use-multi-flow-upload";
48
50
 
49
51
  // Flow Hooks
52
+ export type {
53
+ FlowInputMetadata,
54
+ InputExecutionState,
55
+ UseFlowReturn,
56
+ } from "./hooks/use-flow";
57
+ export { useFlow } from "./hooks/use-flow";
58
+
59
+ export type {
60
+ InputBuilder,
61
+ UseFlowExecutionOptions,
62
+ UseFlowExecutionReturn,
63
+ } from "./hooks/use-flow-execution";
64
+ export { useFlowExecution } from "./hooks/use-flow-execution";
50
65
 
51
66
  // Upload Hooks
52
67
  export type {
@@ -1,2 +0,0 @@
1
- import{a as e,i as t,n,r,t as i}from"./use-upload-C7QZSt1M.mjs";import{useCallback as a}from"react";import{Fragment as o,jsx as s,jsxs as c}from"react/jsx-runtime";function l({flowConfig:t,options:n,children:r}){let i=e({...n,flowConfig:t});return s(o,{children:r({items:i.state.items,totalProgress:i.state.totalProgress,activeUploads:i.state.activeUploads,completedUploads:i.state.completedUploads,failedUploads:i.state.failedUploads,isUploading:i.isUploading,addFiles:i.addFiles,removeFile:i.removeFile,startUpload:i.startUpload,abortUpload:i.abortUpload,abortAll:i.abortAll,clear:i.clear,retryUpload:i.retryUpload})})}function u({item:e,onAbort:t,onRetry:n,onRemove:r}){return c(`div`,{style:{display:`flex`,alignItems:`center`,gap:`12px`,padding:`8px`,borderBottom:`1px solid #eee`},children:[s(`span`,{style:{color:(()=>{switch(e.status){case`success`:return`green`;case`error`:return`red`;case`uploading`:return`blue`;case`aborted`:return`gray`;default:return`black`}})(),fontSize:`18px`},children:(()=>{switch(e.status){case`success`:return`✓`;case`error`:return`✗`;case`uploading`:return`⟳`;case`aborted`:return`⊘`;default:return`○`}})()}),c(`div`,{style:{flex:1,minWidth:0},children:[s(`div`,{style:{fontSize:`14px`,fontWeight:500,overflow:`hidden`,textOverflow:`ellipsis`,whiteSpace:`nowrap`},children:e.file instanceof File?e.file.name:`Upload`}),e.status===`uploading`&&c(`div`,{style:{marginTop:`4px`},children:[s(`progress`,{value:e.progress,max:100,style:{width:`100%`,height:`4px`}}),c(`div`,{style:{fontSize:`12px`,color:`#666`,marginTop:`2px`},children:[e.progress,`% • `,Math.round(e.bytesUploaded/1024),` KB /`,` `,Math.round(e.totalBytes/1024),` KB`]})]}),e.status===`error`&&s(`div`,{style:{fontSize:`12px`,color:`red`,marginTop:`2px`},children:e.error?.message||`Upload failed`}),e.status===`success`&&s(`div`,{style:{fontSize:`12px`,color:`green`,marginTop:`2px`},children:`Upload complete`})]}),c(`div`,{style:{display:`flex`,gap:`8px`},children:[e.status===`uploading`&&s(`button`,{type:`button`,onClick:t,style:{padding:`4px 8px`,fontSize:`12px`,borderRadius:`4px`,border:`1px solid #ccc`,backgroundColor:`#fff`,cursor:`pointer`},children:`Cancel`}),e.status===`error`&&s(`button`,{type:`button`,onClick:n,style:{padding:`4px 8px`,fontSize:`12px`,borderRadius:`4px`,border:`1px solid #ccc`,backgroundColor:`#fff`,cursor:`pointer`},children:`Retry`}),(e.status===`pending`||e.status===`error`||e.status===`aborted`)&&s(`button`,{type:`button`,onClick:r,style:{padding:`4px 8px`,fontSize:`12px`,borderRadius:`4px`,border:`1px solid #ccc`,backgroundColor:`#fff`,cursor:`pointer`},children:`Remove`})]})]})}function d({flowConfig:e,options:t,className:n=``,showFileInput:r=!0,accept:i}){return s(l,{flowConfig:e,options:t,children:({items:e,addFiles:t,startUpload:a,abortUpload:o,retryUpload:l,removeFile:d,totalProgress:f})=>c(`div`,{className:n,children:[r&&s(`div`,{style:{marginBottom:`16px`},children:s(`input`,{type:`file`,multiple:!0,accept:i,onChange:e=>{e.target.files&&(t(e.target.files),a())},style:{padding:`8px`,border:`1px solid #ccc`,borderRadius:`4px`}})}),e.length>0&&c(`div`,{children:[c(`div`,{style:{marginBottom:`8px`,fontSize:`14px`,color:`#666`},children:[`Total Progress: `,f,`%`]}),s(`div`,{style:{border:`1px solid #eee`,borderRadius:`8px`,overflow:`hidden`},children:e.map(e=>s(u,{item:e,onAbort:()=>o(e.id),onRetry:()=>l(e.id),onRemove:()=>d(e.id)},e.id))})]})]})})}function f({flowConfig:e,options:n,accept:i,multiple:a=!1,children:c}){let l=r({...n,flowConfig:e}),u=t({onFilesReceived:e=>{let t=e[0];t&&l.upload(t)},accept:i?[i]:void 0,multiple:a}),d=e=>{let t=e.target.files?.[0];t&&l.upload(t)};return s(o,{children:c({flowUpload:l,dragDrop:u,isActive:u.state.isDragging||u.state.isOver,openFilePicker:u.openFilePicker,getRootProps:()=>u.dragHandlers,getInputProps:()=>({...u.inputProps,onChange:d})})})}function p({flowConfig:e,options:t,accept:n,className:r=``,dragText:i=`Drop files here`,idleText:a=`Drag & drop files or click to browse`}){return s(f,{flowConfig:e,options:t,accept:n,children:({dragDrop:e,flowUpload:t,getRootProps:n,getInputProps:o,openFilePicker:l})=>c(`div`,{...n(),className:r,style:{border:`2px dashed #ccc`,borderRadius:`8px`,padding:`32px`,textAlign:`center`,cursor:`pointer`,backgroundColor:e.state.isDragging?`#f0f0f0`:`transparent`,transition:`background-color 0.2s`},children:[s(`input`,{...o()}),e.state.isDragging&&s(`p`,{style:{margin:0},children:i}),!e.state.isDragging&&!t.isUploading&&t.state.status===`idle`&&c(`div`,{children:[s(`p`,{style:{margin:`0 0 16px 0`},children:a}),s(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),l()},style:{padding:`8px 16px`,borderRadius:`4px`,border:`1px solid #ccc`,backgroundColor:`#fff`,cursor:`pointer`},children:`Choose Files`})]}),t.isUploading&&c(`div`,{children:[s(`progress`,{value:t.state.progress,max:100,style:{width:`100%`,height:`8px`}}),c(`p`,{style:{margin:`8px 0 0 0`},children:[t.state.progress,`%`]}),s(`button`,{type:`button`,onClick:e=>{e.stopPropagation()},style:{marginTop:`8px`,padding:`4px 12px`,borderRadius:`4px`,border:`1px solid #ccc`,backgroundColor:`#fff`,cursor:`pointer`},children:`Cancel`})]}),t.state.status===`success`&&s(`div`,{children:s(`p`,{style:{margin:0,color:`green`},children:`✓ Upload complete!`})}),t.state.status===`error`&&s(`div`,{children:c(`p`,{style:{margin:0,color:`red`},children:[`✗ Error: `,t.state.error?.message]})})]})})}function m({multiUpload:e,filter:t,sortBy:n,children:r}){let i=e.items;t&&(i=i.filter(t)),n&&(i=[...i].sort(n));let a={idle:i.filter(e=>e.state.status===`idle`),uploading:i.filter(e=>e.state.status===`uploading`),success:i.filter(e=>e.state.status===`success`),error:i.filter(e=>e.state.status===`error`),aborted:i.filter(e=>e.state.status===`aborted`)};return s(o,{children:r({items:i,itemsByStatus:a,multiUpload:e,actions:{removeItem:t=>{e.removeItem(t)},retryItem:t=>{e.retryFailed()},abortItem:t=>{e.removeItem(t.id)},startItem:t=>{e.startAll()}}})})}function h({item:e,actions:t,className:n=``,style:r={},showDetails:i=!0}){let a=e=>{switch(e){case`idle`:return`#6c757d`;case`uploading`:return`#007bff`;case`success`:return`#28a745`;case`error`:return`#dc3545`;case`aborted`:return`#6c757d`;default:return`#6c757d`}},l=e=>{switch(e){case`idle`:return`⏳`;case`uploading`:return`📤`;case`success`:return`✅`;case`error`:return`❌`;case`aborted`:return`⏹️`;default:return`❓`}},u=e=>{if(e===0)return`0 Bytes`;let t=1024,n=[`Bytes`,`KB`,`MB`,`GB`],r=Math.floor(Math.log(e)/Math.log(t));return`${parseFloat((e/t**r).toFixed(2))} ${n[r]}`};return c(`div`,{className:`upload-list-item upload-list-item--${e.state.status} ${n}`,style:{padding:`12px`,border:`1px solid #e0e0e0`,borderRadius:`6px`,marginBottom:`8px`,backgroundColor:`#fff`,transition:`all 0.2s ease`,...r},children:[c(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,marginBottom:`8px`},children:[c(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,flex:1},children:[s(`span`,{style:{fontSize:`16px`},children:l(e.state.status)}),s(`span`,{style:{fontWeight:`500`,flex:1},children:e.file instanceof File?e.file.name:`File`})]}),s(`span`,{style:{fontSize:`12px`,color:a(e.state.status),fontWeight:`500`,textTransform:`uppercase`},children:e.state.status})]}),e.state.status===`uploading`&&c(`div`,{style:{marginBottom:`8px`},children:[c(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,marginBottom:`4px`},children:[c(`span`,{style:{fontSize:`12px`,color:`#666`},children:[e.state.progress,`%`]}),i&&e.state.totalBytes&&c(`span`,{style:{fontSize:`12px`,color:`#666`},children:[u(e.state.bytesUploaded),` /`,` `,u(e.state.totalBytes)]})]}),s(`div`,{style:{width:`100%`,height:`6px`,backgroundColor:`#e0e0e0`,borderRadius:`3px`,overflow:`hidden`},children:s(`div`,{style:{width:`${e.state.progress}%`,height:`100%`,backgroundColor:`#007bff`,transition:`width 0.2s ease`}})})]}),i&&c(`div`,{style:{fontSize:`12px`,color:`#666`,marginBottom:`8px`},children:[e.state.totalBytes&&s(`span`,{children:u(e.state.totalBytes)}),e.state.status===`uploading`&&e.state.progress>0&&c(`span`,{children:[` • Progress: `,e.state.progress,`%`]}),e.state.status===`error`&&e.state.error&&s(`div`,{style:{color:`#dc3545`,marginTop:`4px`},children:e.state.error.message})]}),c(`div`,{style:{display:`flex`,gap:`8px`,flexWrap:`wrap`},children:[e.state.status===`idle`&&c(o,{children:[s(`button`,{type:`button`,onClick:()=>t.startItem(e),style:{padding:`4px 8px`,fontSize:`12px`,border:`1px solid #007bff`,backgroundColor:`#007bff`,color:`white`,borderRadius:`4px`,cursor:`pointer`},children:`Start`}),s(`button`,{type:`button`,onClick:()=>t.removeItem(e.id),style:{padding:`4px 8px`,fontSize:`12px`,border:`1px solid #6c757d`,backgroundColor:`transparent`,color:`#6c757d`,borderRadius:`4px`,cursor:`pointer`},children:`Remove`})]}),e.state.status===`uploading`&&s(`button`,{type:`button`,onClick:()=>t.abortItem(e),style:{padding:`4px 8px`,fontSize:`12px`,border:`1px solid #dc3545`,backgroundColor:`transparent`,color:`#dc3545`,borderRadius:`4px`,cursor:`pointer`},children:`Cancel`}),e.state.status===`error`&&c(o,{children:[s(`button`,{type:`button`,onClick:()=>t.retryItem(e),style:{padding:`4px 8px`,fontSize:`12px`,border:`1px solid #28a745`,backgroundColor:`#28a745`,color:`white`,borderRadius:`4px`,cursor:`pointer`},children:`Retry`}),s(`button`,{type:`button`,onClick:()=>t.removeItem(e.id),style:{padding:`4px 8px`,fontSize:`12px`,border:`1px solid #6c757d`,backgroundColor:`transparent`,color:`#6c757d`,borderRadius:`4px`,cursor:`pointer`},children:`Remove`})]}),e.state.status===`success`&&s(`button`,{type:`button`,onClick:()=>t.removeItem(e.id),style:{padding:`4px 8px`,fontSize:`12px`,border:`1px solid #6c757d`,backgroundColor:`transparent`,color:`#6c757d`,borderRadius:`4px`,cursor:`pointer`},children:`Remove`}),e.state.status===`aborted`&&c(o,{children:[s(`button`,{type:`button`,onClick:()=>t.retryItem(e),style:{padding:`4px 8px`,fontSize:`12px`,border:`1px solid #007bff`,backgroundColor:`#007bff`,color:`white`,borderRadius:`4px`,cursor:`pointer`},children:`Retry`}),s(`button`,{type:`button`,onClick:()=>t.removeItem(e.id),style:{padding:`4px 8px`,fontSize:`12px`,border:`1px solid #6c757d`,backgroundColor:`transparent`,color:`#6c757d`,borderRadius:`4px`,cursor:`pointer`},children:`Remove`})]})]})]})}function g({children:e,multiple:r=!0,multiUploadOptions:c={},uploadOptions:l={},onUploadStart:u,onValidationError:d,...f}){let p=i(l),m=n(c),h=a(e=>{let t=[];if(!r&&e.length>1&&t.push(`Single file mode is enabled. Please select only one file. You selected ${e.length} files.`),f.accept&&f.accept.length>0){let n=e.filter(e=>!f.accept?.some(t=>{if(t.startsWith(`.`))return e.name.toLowerCase().endsWith(t.toLowerCase());if(t.endsWith(`/*`)){let n=t.slice(0,-2);return e.type.startsWith(n)}else return e.type===t}));if(n.length>0){let e=n.map(e=>`"${e.name}" (${e.type})`).join(`, `),r=f.accept.join(`, `);t.push(`Invalid file type(s): ${e}. Accepted types: ${r}.`)}}return t.length>0?t:null},[r,f.accept]),g=e=>{u?.(e),r&&m?(m.addFiles(e),setTimeout(()=>m.startAll(),0)):!r&&p&&e.length>0&&e[0]&&p.upload(e[0])},_=a(e=>{console.error(`Upload zone validation errors:`,e),d?.(e)},[d]),v=t({...f,multiple:r,validator:h,onFilesReceived:g,onValidationError:_}),y=v.state.isDragging||v.state.isOver,b=r?m?.state.isUploading??!1:p?.isUploading??!1;return s(o,{children:e({dragDrop:v,upload:p,multiUpload:m,openFilePicker:v.openFilePicker,isActive:y,isProcessing:b})})}function _({className:e=``,style:t={},text:n={},errorStyle:r={},children:i,...a}){let o={idle:a.multiple?`Drag files here or click to select`:`Drag a file here or click to select`,dragging:a.multiple?`Drop files here...`:`Drop file here...`,uploading:`Uploading...`,...n};return i?s(g,{...a,children:i}):s(g,{...a,children:({dragDrop:n,upload:i,multiUpload:a,openFilePicker:l,isActive:u,isProcessing:d})=>c(`button`,{type:`button`,onKeyDown:e=>{(e.key===`Enter`||e.key===` `)&&l()},onKeyUp:e=>{(e.key===`Enter`||e.key===` `)&&l()},...n.dragHandlers,onClick:l,className:`upload-zone ${u?`upload-zone--active`:``} ${d?`upload-zone--processing`:``} ${e}`,style:{border:u?`2px dashed #007bff`:`2px dashed #ccc`,borderRadius:`8px`,padding:`2rem`,textAlign:`center`,cursor:`pointer`,backgroundColor:u?`#f8f9fa`:`transparent`,transition:`all 0.2s ease`,minHeight:`120px`,display:`flex`,flexDirection:`column`,alignItems:`center`,justifyContent:`center`,...t},children:[n.state.isDragging?s(`p`,{style:{margin:0,fontSize:`16px`,color:`#007bff`},children:o.dragging}):d?c(`div`,{style:{textAlign:`center`},children:[s(`p`,{style:{margin:`0 0 10px 0`,fontSize:`14px`},children:o.uploading}),i&&c(`div`,{children:[s(`progress`,{value:i.state.progress,max:100,style:{width:`200px`,height:`8px`}}),c(`p`,{style:{margin:`5px 0 0 0`,fontSize:`12px`,color:`#666`},children:[i.state.progress,`%`]})]}),a&&c(`div`,{children:[s(`progress`,{value:a.state.progress,max:100,style:{width:`200px`,height:`8px`}}),c(`p`,{style:{margin:`5px 0 0 0`,fontSize:`12px`,color:`#666`},children:[a.state.progress,`% (`,a.state.uploading,` `,`uploading, `,a.state.successful,` completed)`]})]})]}):s(`p`,{style:{margin:0,fontSize:`16px`,color:`#666`},children:o.idle}),n.state.errors.length>0&&c(`div`,{style:{marginTop:`10px`,padding:`8px 12px`,backgroundColor:`#f8d7da`,border:`1px solid #f5c6cb`,borderRadius:`4px`,maxWidth:`100%`,...r},children:[s(`p`,{style:{margin:`0 0 5px 0`,fontSize:`12px`,fontWeight:`bold`,color:`#721c24`},children:`Validation Errors:`}),n.state.errors.map((e,t)=>c(`p`,{style:{color:`#721c24`,fontSize:`11px`,margin:`2px 0`,lineHeight:`1.3`},children:[`• `,e]},t))]}),s(`input`,{...n.inputProps})]})})}export{f as a,d as c,m as i,u as l,g as n,p as o,h as r,l as s,_ as t};
2
- //# sourceMappingURL=upload-zone-DN7Gem65.mjs.map