@uploadista/react-native-core 0.0.11 → 0.0.13-beta.1
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/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/types.ts","../src/types/upload-input.ts","../src/components/CameraUploadButton.tsx","../src/components/FileUploadButton.tsx","../src/components/GalleryUploadButton.tsx","../src/components/UploadList.tsx","../src/hooks/use-upload.ts","../src/components/UploadProgress.tsx","../src/client/create-uploadista-client.ts","../src/hooks/use-uploadista-client.ts","../src/hooks/uploadista-context.ts","../src/hooks/use-camera-upload.ts","../src/hooks/use-file-upload.ts","../src/hooks/use-flow-upload.ts","../src/hooks/use-multi-upload.ts","../src/hooks/use-gallery-upload.ts","../src/hooks/use-upload-metrics.ts","../src/hooks/use-uploadista-context.ts","../src/utils/fileHelpers.ts","../src/utils/permissions.ts","../src/utils/uriHelpers.ts"],"sourcesContent":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/types.ts","../src/types/upload-input.ts","../src/components/CameraUploadButton.tsx","../src/components/FileUploadButton.tsx","../src/components/GalleryUploadButton.tsx","../src/components/UploadList.tsx","../src/hooks/use-upload.ts","../src/components/UploadProgress.tsx","../src/client/create-uploadista-client.ts","../src/hooks/use-uploadista-client.ts","../src/hooks/uploadista-context.ts","../src/hooks/use-camera-upload.ts","../src/hooks/use-file-upload.ts","../src/hooks/use-flow-upload.ts","../src/hooks/use-multi-upload.ts","../src/hooks/use-gallery-upload.ts","../src/hooks/use-upload-metrics.ts","../src/hooks/use-uploadista-context.ts","../src/utils/fileHelpers.ts","../src/utils/permissions.ts","../src/utils/uriHelpers.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["initialState: UploadState","initialState","initialState: FlowUploadState","initialState","initialState: MultiUploadState","newItems: UploadItemState[]","result: FilePickResult","parts","getStatusColor","styles","styles","styles","styles"],"sources":["../src/hooks/uploadista-context.ts","../src/hooks/use-uploadista-context.ts","../src/hooks/use-upload.ts","../src/hooks/use-camera-upload.ts","../src/hooks/use-file-upload.ts","../src/hooks/use-flow-upload.ts","../src/hooks/use-multi-upload.ts","../src/hooks/use-gallery-upload.ts","../src/hooks/use-upload-metrics.ts","../src/utils/fileHelpers.ts","../src/utils/permissions.ts","../src/utils/uriHelpers.ts","../src/components/UploadProgress.tsx","../src/components/CameraUploadButton.tsx","../src/components/FileUploadButton.tsx","../src/components/GalleryUploadButton.tsx","../src/components/UploadList.tsx"],"sourcesContent":["import type { UploadistaEvent } from \"@uploadista/client-core\";\nimport { createContext } from \"react\";\nimport type { FileSystemProvider } from \"../types\";\nimport type { UseUploadistaClientReturn } from \"./use-uploadista-client\";\n\nexport interface UploadistaContextType extends UseUploadistaClientReturn {\n fileSystemProvider: FileSystemProvider;\n /**\n * Subscribe to events (used internally by hooks)\n * @internal\n */\n subscribeToEvents: (handler: (event: UploadistaEvent) => void) => () => void;\n}\n\nexport const UploadistaContext = createContext<\n UploadistaContextType | undefined\n>(undefined);\n","import { useContext } from \"react\";\nimport { UploadistaContext } from \"./uploadista-context\";\n\n/**\n * Hook to access the Uploadista client instance\n * Must be used within an UploadistaProvider\n * @throws Error if used outside of UploadistaProvider\n * @returns The Uploadista client and file system provider\n */\nexport function useUploadistaContext() {\n const context = useContext(UploadistaContext);\n\n if (!context) {\n throw new Error(\n \"useUploadistaClient must be used within an UploadistaProvider\",\n );\n }\n\n return context;\n}\n","import type { UploadistaEvent } from \"@uploadista/client-core\";\nimport type { UploadFile } from \"@uploadista/core/types\";\nimport { UploadEventType } from \"@uploadista/core/types\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { FilePickResult } from \"../types\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\nexport type UploadStatus =\n | \"idle\"\n | \"uploading\"\n | \"success\"\n | \"error\"\n | \"aborted\";\n\nexport interface UploadState {\n status: UploadStatus;\n progress: number;\n bytesUploaded: number;\n totalBytes: number | null;\n error: Error | null;\n result: UploadFile | null;\n}\n\nexport interface UseUploadOptions {\n /**\n * Upload metadata to attach to the file\n */\n metadata?: Record<string, string>;\n\n /**\n * Whether to defer the upload size calculation\n */\n uploadLengthDeferred?: boolean;\n\n /**\n * Manual upload size override\n */\n uploadSize?: number;\n\n /**\n * Called when upload progress updates\n */\n onProgress?: (\n progress: number,\n bytesUploaded: number,\n totalBytes: number | null,\n ) => void;\n\n /**\n * Called when a chunk completes\n */\n onChunkComplete?: (\n chunkSize: number,\n bytesAccepted: number,\n bytesTotal: number | null,\n ) => void;\n\n /**\n * Called when upload succeeds\n */\n onSuccess?: (result: UploadFile) => void;\n\n /**\n * Called when upload fails\n */\n onError?: (error: Error) => void;\n\n /**\n * Called when upload is aborted\n */\n onAbort?: () => void;\n\n /**\n * Custom retry logic\n */\n onShouldRetry?: (error: Error, retryAttempt: number) => boolean;\n}\n\nexport interface UseUploadReturn {\n /**\n * Current upload state\n */\n state: UploadState;\n\n /**\n * Start uploading a file from a file pick result\n */\n upload: (file: FilePickResult) => Promise<void>;\n\n /**\n * Abort the current upload\n */\n abort: () => void;\n\n /**\n * Reset the upload state to idle\n */\n reset: () => void;\n\n /**\n * Retry the last failed upload\n */\n retry: () => void;\n\n /**\n * Whether an upload is currently active\n */\n isUploading: boolean;\n\n /**\n * Whether the upload can be retried\n */\n canRetry: boolean;\n}\n\nconst initialState: UploadState = {\n status: \"idle\",\n progress: 0,\n bytesUploaded: 0,\n totalBytes: null,\n error: null,\n result: null,\n};\n\n/**\n * React hook for managing individual file uploads with full state management.\n * Provides upload progress tracking, error handling, abort functionality, and retry logic.\n *\n * Must be used within an UploadistaProvider.\n *\n * @param options - Upload configuration and event handlers\n * @returns Upload state and control methods\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const upload = useUpload({\n * onSuccess: (result) => console.log('Upload complete:', result),\n * onError: (error) => console.error('Upload failed:', error),\n * onProgress: (progress) => console.log('Progress:', progress + '%'),\n * });\n *\n * const handlePickFile = async () => {\n * const file = await fileSystemProvider.pickDocument();\n * if (file) {\n * await upload.upload(file);\n * }\n * };\n *\n * return (\n * <View>\n * <Button title=\"Pick File\" onPress={handlePickFile} />\n * {upload.isUploading && <Text>Progress: {upload.state.progress}%</Text>}\n * {upload.state.error && <Text>Error: {upload.state.error.message}</Text>}\n * {upload.canRetry && <Button title=\"Retry\" onPress={upload.retry} />}\n * <Button title=\"Abort\" onPress={upload.abort} disabled={!upload.isUploading} />\n * </View>\n * );\n * }\n * ```\n */\nexport function useUpload(options: UseUploadOptions = {}): UseUploadReturn {\n const { client, fileSystemProvider, subscribeToEvents } =\n useUploadistaContext();\n const [state, setState] = useState<UploadState>(initialState);\n const abortControllerRef = useRef<{ abort: () => void } | null>(null);\n const lastFileRef = useRef<FilePickResult | null>(null);\n const currentUploadIdRef = useRef<string | null>(null);\n\n const updateState = useCallback((update: Partial<UploadState>) => {\n setState((prev) => ({ ...prev, ...update }));\n }, []);\n\n const reset = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n abortControllerRef.current = null;\n }\n setState(initialState);\n lastFileRef.current = null;\n currentUploadIdRef.current = null;\n }, []);\n\n const abort = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n abortControllerRef.current = null;\n }\n\n updateState({\n status: \"aborted\",\n });\n\n options.onAbort?.();\n }, [options, updateState]);\n\n const upload = useCallback(\n async (file: FilePickResult) => {\n // Handle cancelled picker\n if (file.status === \"cancelled\") {\n return;\n }\n\n // Handle picker error\n if (file.status === \"error\") {\n updateState({\n status: \"error\",\n error: file.error,\n });\n options.onError?.(file.error);\n return;\n }\n\n // Reset any previous state\n setState({\n ...initialState,\n status: \"uploading\",\n totalBytes: file.data.size,\n });\n\n lastFileRef.current = file;\n\n try {\n // Read file content\n const fileContent = await fileSystemProvider.readFile(file.data.uri);\n\n // Create a Blob from the file content\n // Convert ArrayBuffer to Uint8Array for better compatibility\n const data =\n fileContent instanceof ArrayBuffer\n ? new Uint8Array(fileContent)\n : fileContent;\n // Note: Using any cast here because React Native Blob accepts BufferSource\n // but TypeScript's lib.dom.d.ts Blob type doesn't include it\n // biome-ignore lint/suspicious/noExplicitAny: React Native Blob accepts BufferSource\n const blob = new Blob([data as any], {\n type: file.data.mimeType || \"application/octet-stream\",\n // biome-ignore lint/suspicious/noExplicitAny: BlobPropertyBag type differs by platform\n } as any);\n\n // use the Blob (for React Native)\n const uploadInput = blob;\n\n // Start the upload using the client\n const uploadPromise = client.upload(uploadInput, {\n metadata: options.metadata,\n uploadLengthDeferred: options.uploadLengthDeferred,\n uploadSize: options.uploadSize,\n\n onStart: ({ uploadId }) => {\n currentUploadIdRef.current = uploadId;\n },\n\n onProgress: (\n _uploadId: string,\n bytesUploaded: number,\n totalBytes: number | null,\n ) => {\n const progress = totalBytes\n ? Math.round((bytesUploaded / totalBytes) * 100)\n : 0;\n\n updateState({\n progress,\n bytesUploaded,\n totalBytes,\n });\n\n options.onProgress?.(progress, bytesUploaded, totalBytes);\n },\n\n onChunkComplete: (\n chunkSize: number,\n bytesAccepted: number,\n bytesTotal: number | null,\n ) => {\n options.onChunkComplete?.(chunkSize, bytesAccepted, bytesTotal);\n },\n\n onSuccess: (result: UploadFile) => {\n updateState({\n status: \"success\",\n result,\n progress: 100,\n bytesUploaded: result.size || 0,\n totalBytes: result.size || null,\n });\n\n options.onSuccess?.(result);\n abortControllerRef.current = null;\n },\n\n onError: (error: Error) => {\n updateState({\n status: \"error\",\n error,\n });\n\n options.onError?.(error);\n abortControllerRef.current = null;\n },\n\n onShouldRetry: options.onShouldRetry,\n });\n\n // Handle the promise to get the abort controller\n const controller = await uploadPromise;\n abortControllerRef.current = controller;\n } catch (error) {\n updateState({\n status: \"error\",\n error: error as Error,\n });\n\n options.onError?.(error as Error);\n abortControllerRef.current = null;\n }\n },\n [client, fileSystemProvider, options, updateState],\n );\n\n const retry = useCallback(() => {\n if (\n lastFileRef.current &&\n (state.status === \"error\" || state.status === \"aborted\")\n ) {\n upload(lastFileRef.current);\n }\n }, [upload, state.status]);\n\n // Subscribe to events from context (WebSocket events)\n useEffect(() => {\n const unsubscribe = subscribeToEvents((event: UploadistaEvent) => {\n // Handle upload progress events\n const uploadEvent = event as {\n type: string;\n data?: { id: string; progress: number; total: number };\n };\n\n if (\n uploadEvent.type === UploadEventType.UPLOAD_PROGRESS &&\n uploadEvent.data\n ) {\n const {\n id: uploadId,\n progress: bytesUploaded,\n total: totalBytes,\n } = uploadEvent.data;\n\n if (uploadId !== currentUploadIdRef.current) {\n return;\n }\n\n // Update state for this upload\n const progress = totalBytes\n ? Math.round((bytesUploaded / totalBytes) * 100)\n : 0;\n\n setState((prev) => {\n // Only update if we're currently uploading\n if (prev.status === \"uploading\") {\n return {\n ...prev,\n progress,\n bytesUploaded,\n totalBytes,\n };\n }\n return prev;\n });\n\n options.onProgress?.(progress, bytesUploaded, totalBytes);\n }\n });\n\n return unsubscribe;\n }, [subscribeToEvents, options]);\n\n const isUploading = state.status === \"uploading\";\n const canRetry =\n (state.status === \"error\" || state.status === \"aborted\") &&\n lastFileRef.current !== null;\n\n return {\n state,\n upload,\n abort,\n reset,\n retry,\n isUploading,\n canRetry,\n };\n}\n","import { useCallback } from \"react\";\nimport type { UseCameraUploadOptions } from \"../types\";\nimport { useUpload } from \"./use-upload\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\n/**\n * Hook for capturing photos and uploading them\n * Handles camera permissions and capture flow\n * @param options - Camera upload configuration\n * @returns Upload state and camera capture/upload function\n */\nexport function useCameraUpload(options?: UseCameraUploadOptions) {\n const { fileSystemProvider } = useUploadistaContext();\n const uploadHook = useUpload({\n metadata: options?.metadata,\n onSuccess: options?.onSuccess,\n onError: options?.onError,\n onProgress: options?.onProgress,\n });\n\n // Capture and upload photo\n const captureAndUpload = useCallback(async () => {\n try {\n // Capture photo with camera\n const photo = await fileSystemProvider.pickCamera(options?.cameraOptions);\n\n // Upload captured photo\n await uploadHook.upload(photo);\n } catch (error) {\n console.error(\"Camera capture error:\", error);\n }\n }, [fileSystemProvider, options?.cameraOptions, uploadHook]);\n\n return {\n ...uploadHook,\n captureAndUpload,\n };\n}\n","import { useCallback } from \"react\";\nimport type { UseFileUploadOptions } from \"../types\";\nimport { useUpload } from \"./use-upload\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\n/**\n * Hook for selecting and uploading generic files (documents, etc.)\n * @param options - File upload configuration\n * @returns Upload state and file picker/upload function\n */\nexport function useFileUpload(options?: UseFileUploadOptions) {\n const { fileSystemProvider } = useUploadistaContext();\n const uploadHook = useUpload({\n metadata: options?.metadata,\n onSuccess: options?.onSuccess,\n onError: options?.onError,\n onProgress: options?.onProgress,\n });\n\n // Pick and upload file\n const pickAndUpload = useCallback(async () => {\n try {\n // Pick file\n const file = await fileSystemProvider.pickDocument({\n allowedTypes: options?.allowedTypes,\n });\n\n // Upload file\n await uploadHook.upload(file);\n } catch (error) {\n console.error(\"File selection error:\", error);\n throw error;\n }\n }, [fileSystemProvider, options?.allowedTypes, uploadHook]);\n\n return {\n ...uploadHook,\n pickAndUpload,\n };\n}\n","import type { UploadFile } from \"@uploadista/core/types\";\nimport { useCallback, useRef, useState } from \"react\";\nimport type { FilePickResult, UseFlowUploadOptions } from \"../types\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\nexport type FlowUploadStatus =\n | \"idle\"\n | \"uploading\"\n | \"processing\"\n | \"success\"\n | \"error\"\n | \"aborted\";\n\nexport interface FlowUploadState {\n status: FlowUploadStatus;\n progress: number;\n bytesUploaded: number;\n totalBytes: number | null;\n jobId: string | null;\n error: Error | null;\n result: unknown | null;\n}\n\nconst initialState: FlowUploadState = {\n status: \"idle\",\n progress: 0,\n bytesUploaded: 0,\n totalBytes: null,\n jobId: null,\n error: null,\n result: null,\n};\n\n/**\n * Hook for uploading files through a flow pipeline with full state management.\n * Provides upload progress tracking, flow execution monitoring, error handling, and abort functionality.\n *\n * Must be used within an UploadistaProvider.\n *\n * @param options - Flow upload configuration\n * @returns Flow upload state and control methods\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const flowUpload = useFlowUpload({\n * flowId: 'image-processing-flow',\n * storageId: 'my-storage',\n * onSuccess: (result) => console.log('Flow complete:', result),\n * onError: (error) => console.error('Flow failed:', error),\n * onProgress: (progress) => console.log('Progress:', progress + '%'),\n * });\n *\n * const handlePickFile = async () => {\n * const file = await fileSystemProvider.pickDocument();\n * if (file) {\n * await flowUpload.upload(file);\n * }\n * };\n *\n * return (\n * <View>\n * <Button title=\"Pick File\" onPress={handlePickFile} />\n * {flowUpload.isUploading && <Text>Progress: {flowUpload.state.progress}%</Text>}\n * {flowUpload.state.jobId && <Text>Job ID: {flowUpload.state.jobId}</Text>}\n * {flowUpload.state.error && <Text>Error: {flowUpload.state.error.message}</Text>}\n * <Button title=\"Abort\" onPress={flowUpload.abort} disabled={!flowUpload.isActive} />\n * </View>\n * );\n * }\n * ```\n */\nexport function useFlowUpload(options: UseFlowUploadOptions) {\n const { client, fileSystemProvider } = useUploadistaContext();\n const [state, setState] = useState<FlowUploadState>(initialState);\n const abortControllerRef = useRef<{ abort: () => void } | null>(null);\n const lastFileRef = useRef<FilePickResult | null>(null);\n\n const updateState = useCallback((update: Partial<FlowUploadState>) => {\n setState((prev) => ({ ...prev, ...update }));\n }, []);\n\n const reset = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n abortControllerRef.current = null;\n }\n setState(initialState);\n lastFileRef.current = null;\n }, []);\n\n const abort = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n abortControllerRef.current = null;\n }\n\n updateState({\n status: \"aborted\",\n });\n }, [updateState]);\n\n const upload = useCallback(\n async (file: FilePickResult) => {\n // Handle cancelled picker\n if (file.status === \"cancelled\") {\n return;\n }\n\n // Handle picker error\n if (file.status === \"error\") {\n updateState({\n status: \"error\",\n error: file.error,\n });\n options.onError?.(file.error);\n return;\n }\n\n // Reset any previous state\n setState({\n ...initialState,\n status: \"uploading\",\n totalBytes: file.data.size,\n });\n\n lastFileRef.current = file;\n\n try {\n // Read file content\n const fileContent = await fileSystemProvider.readFile(file.data.uri);\n\n // Create a Blob from the file content\n // Convert ArrayBuffer to Uint8Array for better compatibility\n const data =\n fileContent instanceof ArrayBuffer\n ? new Uint8Array(fileContent)\n : fileContent;\n // Note: Using any cast here because React Native Blob accepts BufferSource\n // but TypeScript's lib.dom.d.ts Blob type doesn't include it\n // biome-ignore lint/suspicious/noExplicitAny: React Native Blob accepts BufferSource\n const blob = new Blob([data as any], {\n type: file.data.mimeType || \"application/octet-stream\",\n // biome-ignore lint/suspicious/noExplicitAny: BlobPropertyBag type differs by platform\n } as any);\n\n // use the Blob (for React Native)\n const uploadInput = blob;\n\n // Start the flow upload using the client\n const uploadPromise = client.uploadWithFlow(\n uploadInput,\n {\n flowId: options.flowId,\n storageId: options.storageId,\n outputNodeId: options.outputNodeId,\n metadata: options.metadata as Record<string, string> | undefined,\n },\n {\n onJobStart: () => {\n updateState({\n status: \"processing\",\n });\n },\n\n onProgress: (\n _uploadId: string,\n bytesUploaded: number,\n totalBytes: number | null,\n ) => {\n const progress = totalBytes\n ? Math.round((bytesUploaded / totalBytes) * 100)\n : 0;\n\n updateState({\n progress,\n bytesUploaded,\n totalBytes,\n });\n\n options.onProgress?.(progress, bytesUploaded, totalBytes);\n },\n\n onChunkComplete: (\n chunkSize: number,\n bytesAccepted: number,\n bytesTotal: number | null,\n ) => {\n options.onChunkComplete?.(chunkSize, bytesAccepted, bytesTotal);\n },\n\n onSuccess: (result: UploadFile) => {\n updateState({\n status: \"success\",\n result,\n progress: 100,\n bytesUploaded: result.size || 0,\n totalBytes: result.size || null,\n });\n\n options.onSuccess?.(result);\n abortControllerRef.current = null;\n },\n\n onError: (error: Error) => {\n updateState({\n status: \"error\",\n error,\n });\n\n options.onError?.(error);\n abortControllerRef.current = null;\n },\n },\n );\n\n // Handle the promise to get the abort controller\n const controller = await uploadPromise;\n abortControllerRef.current = controller;\n } catch (error) {\n updateState({\n status: \"error\",\n error: error as Error,\n });\n\n options.onError?.(error as Error);\n abortControllerRef.current = null;\n }\n },\n [client, fileSystemProvider, options, updateState],\n );\n\n const retry = useCallback(() => {\n if (\n lastFileRef.current &&\n (state.status === \"error\" || state.status === \"aborted\")\n ) {\n upload(lastFileRef.current);\n }\n }, [upload, state.status]);\n\n const isActive =\n state.status === \"uploading\" || state.status === \"processing\";\n const canRetry =\n (state.status === \"error\" || state.status === \"aborted\") &&\n lastFileRef.current !== null;\n\n return {\n state,\n upload,\n abort,\n reset,\n retry,\n isActive,\n canRetry,\n };\n}\n","import type { UploadFile } from \"@uploadista/core/types\";\nimport { useCallback, useRef, useState } from \"react\";\nimport type { FilePickResult, UseMultiUploadOptions } from \"../types\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\nexport interface UploadItemState {\n id: string;\n file: Extract<FilePickResult, { status: \"success\" }>;\n status: \"idle\" | \"uploading\" | \"success\" | \"error\" | \"aborted\";\n progress: number;\n bytesUploaded: number;\n totalBytes: number;\n error: Error | null;\n result: UploadFile | null;\n}\n\nexport interface MultiUploadState {\n items: UploadItemState[];\n totalProgress: number;\n totalUploaded: number;\n totalBytes: number;\n activeCount: number;\n completedCount: number;\n failedCount: number;\n}\n\nconst initialState: MultiUploadState = {\n items: [],\n totalProgress: 0,\n totalUploaded: 0,\n totalBytes: 0,\n activeCount: 0,\n completedCount: 0,\n failedCount: 0,\n};\n\n/**\n * Hook for managing multiple concurrent file uploads with progress tracking.\n * Each file is uploaded independently using the core upload client.\n *\n * Must be used within an UploadistaProvider.\n *\n * @param options - Multi-upload configuration options\n * @returns Multi-upload state and control methods\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const multiUpload = useMultiUpload({\n * maxConcurrent: 3,\n * onSuccess: (result) => console.log('File uploaded:', result),\n * onError: (error) => console.error('Upload failed:', error),\n * });\n *\n * const handlePickFiles = async () => {\n * const files = await fileSystemProvider.pickImage({ allowMultiple: true });\n * multiUpload.addFiles(files);\n * await multiUpload.startUploads();\n * };\n *\n * return (\n * <View>\n * <Button title=\"Pick Files\" onPress={handlePickFiles} />\n * <Text>Progress: {multiUpload.state.totalProgress}%</Text>\n * <Text>Active: {multiUpload.state.activeCount}</Text>\n * <Text>Completed: {multiUpload.state.completedCount}/{multiUpload.state.items.length}</Text>\n * </View>\n * );\n * }\n * ```\n */\nexport function useMultiUpload(options: UseMultiUploadOptions = {}) {\n const { client } = useUploadistaContext();\n const [state, setState] = useState<MultiUploadState>(initialState);\n const abortControllersRef = useRef<Map<string, { abort: () => void }>>(\n new Map(),\n );\n const nextIdRef = useRef(0);\n // Use ref to track items synchronously\n const itemsRef = useRef<UploadItemState[]>([]);\n\n const generateId = useCallback(() => {\n return `upload-${Date.now()}-${nextIdRef.current++}`;\n }, []);\n\n const updateAggregateStats = useCallback((items: UploadItemState[]) => {\n const totalBytes = items.reduce((sum, item) => sum + item.totalBytes, 0);\n const totalUploaded = items.reduce(\n (sum, item) => sum + item.bytesUploaded,\n 0,\n );\n const totalProgress =\n totalBytes > 0 ? Math.round((totalUploaded / totalBytes) * 100) : 0;\n const activeCount = items.filter(\n (item) => item.status === \"uploading\",\n ).length;\n const completedCount = items.filter(\n (item) => item.status === \"success\",\n ).length;\n const failedCount = items.filter((item) => item.status === \"error\").length;\n\n // Update ref synchronously\n itemsRef.current = items;\n\n setState((prev) => ({\n ...prev,\n items,\n totalProgress,\n totalUploaded,\n totalBytes,\n activeCount,\n completedCount,\n failedCount,\n }));\n }, []);\n\n const addFiles = useCallback(\n (files: FilePickResult[]) => {\n // Filter out cancelled and error results, only keep successful picks\n const successfulFiles = files.filter(\n (file): file is Extract<FilePickResult, { status: \"success\" }> =>\n file.status === \"success\",\n );\n\n const newItems: UploadItemState[] = successfulFiles.map((file) => ({\n id: generateId(),\n file,\n status: \"idle\" as const,\n progress: 0,\n bytesUploaded: 0,\n totalBytes: file.data.size,\n error: null,\n result: null,\n }));\n\n // Update ref synchronously\n const updatedItems = [...itemsRef.current, ...newItems];\n itemsRef.current = updatedItems;\n\n setState((prev) => {\n const totalBytes = updatedItems.reduce(\n (sum, item) => sum + item.totalBytes,\n 0,\n );\n return {\n ...prev,\n items: updatedItems,\n totalBytes,\n };\n });\n\n return newItems.map((item) => item.id);\n },\n [generateId],\n );\n\n const uploadSingleItem = useCallback(\n async (item: UploadItemState) => {\n try {\n console.log(\"Uploading item:\", item.file.data.name);\n // Update status to uploading\n const updatedItems = itemsRef.current.map((i) =>\n i.id === item.id ? { ...i, status: \"uploading\" as const } : i,\n );\n updateAggregateStats(updatedItems);\n\n // Convert file URI to Blob using fetch (React Native compatible)\n // React Native's Blob doesn't support ArrayBuffer/Uint8Array constructor\n const response = await fetch(item.file.data.uri);\n const blob = await response.blob();\n\n // Override blob type if we have mimeType from picker\n const uploadInput = item.file.data.mimeType\n ? new Blob([blob], { type: item.file.data.mimeType })\n : blob;\n\n // Start upload using the client\n console.log(\"Uploading input:\", uploadInput);\n const uploadPromise = client.upload(uploadInput, {\n metadata: options.metadata,\n\n onProgress: (\n _uploadId: string,\n bytesUploaded: number,\n totalBytes: number | null,\n ) => {\n const progress = totalBytes\n ? Math.round((bytesUploaded / totalBytes) * 100)\n : 0;\n\n const updatedItems = itemsRef.current.map((i) =>\n i.id === item.id\n ? {\n ...i,\n progress,\n bytesUploaded,\n totalBytes: totalBytes || i.totalBytes,\n }\n : i,\n );\n updateAggregateStats(updatedItems);\n },\n\n onSuccess: (result: UploadFile) => {\n const updatedItems = itemsRef.current.map((i) =>\n i.id === item.id\n ? {\n ...i,\n status: \"success\" as const,\n progress: 100,\n result,\n bytesUploaded: result.size || i.totalBytes,\n }\n : i,\n );\n updateAggregateStats(updatedItems);\n\n options.onSuccess?.(result);\n abortControllersRef.current.delete(item.id);\n },\n\n onError: (error: Error) => {\n const updatedItems = itemsRef.current.map((i) =>\n i.id === item.id\n ? { ...i, status: \"error\" as const, error }\n : i,\n );\n updateAggregateStats(updatedItems);\n\n options.onError?.(error);\n abortControllersRef.current.delete(item.id);\n },\n });\n\n // Store abort controller\n const controller = await uploadPromise;\n abortControllersRef.current.set(item.id, controller);\n } catch (error) {\n console.error(\"Error uploading item:\", error);\n const updatedItems = itemsRef.current.map((i) =>\n i.id === item.id\n ? {\n ...i,\n status: \"error\" as const,\n error: error as Error,\n }\n : i,\n );\n updateAggregateStats(updatedItems);\n\n options.onError?.(error as Error);\n abortControllersRef.current.delete(item.id);\n }\n },\n [client, options, updateAggregateStats],\n );\n\n const startUploads = useCallback(\n async (itemIds?: string[]) => {\n const maxConcurrent = options.maxConcurrent || 3;\n\n // Get items from ref (synchronous access to latest items)\n const itemsToUpload = itemIds\n ? itemsRef.current.filter(\n (item) => itemIds.includes(item.id) && item.status === \"idle\",\n )\n : itemsRef.current.filter((item) => item.status === \"idle\");\n\n console.log(\"Items to upload:\", itemsToUpload.length, itemsToUpload);\n\n // Process items in batches\n for (let i = 0; i < itemsToUpload.length; i += maxConcurrent) {\n const batch = itemsToUpload.slice(i, i + maxConcurrent);\n await Promise.all(batch.map((item) => uploadSingleItem(item)));\n }\n },\n [options.maxConcurrent, uploadSingleItem],\n );\n\n const removeItem = useCallback(\n (id: string) => {\n const controller = abortControllersRef.current.get(id);\n if (controller) {\n controller.abort();\n abortControllersRef.current.delete(id);\n }\n\n const updatedItems = itemsRef.current.filter((item) => item.id !== id);\n updateAggregateStats(updatedItems);\n },\n [updateAggregateStats],\n );\n\n const abortItem = useCallback(\n (id: string) => {\n const controller = abortControllersRef.current.get(id);\n if (controller) {\n controller.abort();\n abortControllersRef.current.delete(id);\n }\n\n const updatedItems = itemsRef.current.map((item) =>\n item.id === id ? { ...item, status: \"aborted\" as const } : item,\n );\n updateAggregateStats(updatedItems);\n },\n [updateAggregateStats],\n );\n\n const clear = useCallback(() => {\n // Abort all active uploads\n abortControllersRef.current.forEach((controller) => {\n controller.abort();\n });\n abortControllersRef.current.clear();\n\n // Clear ref\n itemsRef.current = [];\n\n setState(initialState);\n }, []);\n\n const retryItem = useCallback(\n async (id: string) => {\n const item = itemsRef.current.find((i) => i.id === id);\n if (item && (item.status === \"error\" || item.status === \"aborted\")) {\n // Reset item status to idle\n const updatedItems = itemsRef.current.map((i) =>\n i.id === id\n ? {\n ...i,\n status: \"idle\" as const,\n progress: 0,\n bytesUploaded: 0,\n error: null,\n }\n : i,\n );\n updateAggregateStats(updatedItems);\n\n // Upload it (get the reset item from the updated items)\n const resetItem = itemsRef.current.find((i) => i.id === id);\n if (resetItem) {\n await uploadSingleItem(resetItem);\n }\n }\n },\n [uploadSingleItem, updateAggregateStats],\n );\n\n return {\n state,\n addFiles,\n startUploads,\n removeItem,\n abortItem,\n retryItem,\n clear,\n };\n}\n","import { useCallback } from \"react\";\nimport type { FilePickResult, UseGalleryUploadOptions } from \"../types\";\nimport { useMultiUpload } from \"./use-multi-upload\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\n/**\n * Hook for selecting and uploading photos/videos from gallery\n * Handles batch selection and concurrent uploads\n * @param options - Gallery upload configuration\n * @returns Upload state and gallery selection/upload function\n */\nexport function useGalleryUpload(options?: UseGalleryUploadOptions) {\n const { fileSystemProvider } = useUploadistaContext();\n const uploadHook = useMultiUpload({\n maxConcurrent: 3,\n metadata: options?.metadata,\n onSuccess: options?.onSuccess,\n onError: options?.onError,\n });\n\n // Select and upload media from gallery\n const selectAndUpload = useCallback(async () => {\n let result: FilePickResult;\n\n // Select appropriate media type\n if (options?.mediaType === \"video\") {\n result = await fileSystemProvider.pickVideo({\n allowMultiple: options?.allowMultiple ?? true,\n });\n } else if (options?.mediaType === \"photo\") {\n result = await fileSystemProvider.pickImage({\n allowMultiple: options?.allowMultiple ?? true,\n });\n } else {\n // For 'mixed' or default, use pickImage first (can be extended to support both)\n result = await fileSystemProvider.pickImage({\n allowMultiple: options?.allowMultiple ?? true,\n });\n }\n\n // Handle cancelled picker\n if (result.status === \"cancelled\") {\n return [];\n }\n\n // Handle picker error\n if (result.status === \"error\") {\n console.error(\"Gallery selection error:\", result.error);\n options?.onError?.(result.error);\n return [];\n }\n\n // Success - add file and start upload\n const itemIds = uploadHook.addFiles([result]);\n console.log(\"starting uploads\", itemIds);\n await uploadHook.startUploads(itemIds);\n console.log(\"uploads started\", itemIds);\n\n return itemIds;\n }, [\n fileSystemProvider,\n options?.allowMultiple,\n options?.mediaType,\n options?.onError,\n uploadHook,\n ]);\n\n return {\n ...uploadHook,\n selectAndUpload,\n };\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport type { UploadMetrics } from \"../types\";\n\n/**\n * Hook for tracking upload performance metrics\n * @returns Metrics object and methods to track uploads\n */\nexport function useUploadMetrics() {\n const startTimeRef = useRef<number | null>(null);\n const startBytesRef = useRef<number>(0);\n const peakSpeedRef = useRef<number>(0);\n\n const [metrics, setMetrics] = useState<UploadMetrics>({\n totalBytes: 0,\n durationMs: 0,\n avgSpeed: 0,\n peakSpeed: 0,\n retries: 0,\n });\n\n // Start tracking\n const start = useCallback(() => {\n startTimeRef.current = Date.now();\n startBytesRef.current = 0;\n peakSpeedRef.current = 0;\n }, []);\n\n // Update metrics based on current progress\n const update = useCallback(\n (uploadedBytes: number, _totalBytes: number, currentRetries = 0) => {\n if (!startTimeRef.current) {\n return;\n }\n\n const now = Date.now();\n const durationMs = now - startTimeRef.current;\n const speed = durationMs > 0 ? (uploadedBytes / durationMs) * 1000 : 0;\n\n if (speed > peakSpeedRef.current) {\n peakSpeedRef.current = speed;\n }\n\n setMetrics({\n totalBytes: uploadedBytes,\n durationMs,\n avgSpeed: durationMs > 0 ? (uploadedBytes / durationMs) * 1000 : 0,\n peakSpeed: peakSpeedRef.current,\n retries: currentRetries,\n });\n },\n [],\n );\n\n // End tracking and return final metrics\n const end = useCallback(() => {\n const finalMetrics = metrics;\n startTimeRef.current = null;\n return finalMetrics;\n }, [metrics]);\n\n // Reset metrics\n const reset = useCallback(() => {\n startTimeRef.current = null;\n startBytesRef.current = 0;\n peakSpeedRef.current = 0;\n setMetrics({\n totalBytes: 0,\n durationMs: 0,\n avgSpeed: 0,\n peakSpeed: 0,\n retries: 0,\n });\n }, []);\n\n return {\n metrics,\n start,\n update,\n end,\n reset,\n };\n}\n","/**\n * File utility functions for React Native uploads\n */\n\n/**\n * Format file size to human readable string\n * @param bytes - Size in bytes\n * @returns Formatted size string (e.g., \"1.5 MB\")\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes === 0) return \"0 Bytes\";\n\n const k = 1024;\n const sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n\n return `${Math.round((bytes / k ** i) * 100) / 100} ${sizes[i]}`;\n}\n\n/**\n * Get MIME type from file name\n * @param fileName - File name with extension\n * @returns MIME type or 'application/octet-stream' as fallback\n */\nexport function getMimeTypeFromFileName(fileName: string): string {\n const mimeTypes: Record<string, string> = {\n // Images\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".png\": \"image/png\",\n \".gif\": \"image/gif\",\n \".bmp\": \"image/bmp\",\n \".webp\": \"image/webp\",\n \".svg\": \"image/svg+xml\",\n\n // Videos\n \".mp4\": \"video/mp4\",\n \".avi\": \"video/x-msvideo\",\n \".mov\": \"video/quicktime\",\n \".wmv\": \"video/x-ms-wmv\",\n \".flv\": \"video/x-flv\",\n \".mkv\": \"video/x-matroska\",\n \".webm\": \"video/webm\",\n\n // Audio\n \".mp3\": \"audio/mpeg\",\n \".wav\": \"audio/wav\",\n \".aac\": \"audio/aac\",\n \".flac\": \"audio/flac\",\n \".m4a\": \"audio/mp4\",\n\n // Documents\n \".pdf\": \"application/pdf\",\n \".doc\": \"application/msword\",\n \".docx\":\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n \".xls\": \"application/vnd.ms-excel\",\n \".xlsx\":\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n \".ppt\": \"application/vnd.ms-powerpoint\",\n \".pptx\":\n \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n \".txt\": \"text/plain\",\n \".csv\": \"text/csv\",\n \".json\": \"application/json\",\n \".xml\": \"application/xml\",\n \".zip\": \"application/zip\",\n };\n\n const ext = fileName.toLowerCase().slice(fileName.lastIndexOf(\".\"));\n return mimeTypes[ext] || \"application/octet-stream\";\n}\n\n/**\n * Check if file type is allowed\n * @param fileName - File name to check\n * @param allowedTypes - Array of allowed MIME types (e.g., ['image/jpeg', 'image/png'])\n * @returns True if file type is allowed\n */\nexport function isFileTypeAllowed(\n fileName: string,\n allowedTypes: string[],\n): boolean {\n if (!allowedTypes || allowedTypes.length === 0) {\n return true;\n }\n\n const mimeType = getMimeTypeFromFileName(fileName);\n return allowedTypes.some((allowed) => {\n if (allowed.endsWith(\"/*\")) {\n // Handle wildcard patterns like 'image/*'\n const [type] = allowed.split(\"/\");\n return mimeType.startsWith(`${type}/`);\n }\n return allowed === mimeType;\n });\n}\n\n/**\n * Check if file size is within limits\n * @param fileSize - File size in bytes\n * @param maxSize - Maximum allowed size in bytes (optional)\n * @param minSize - Minimum allowed size in bytes (optional)\n * @returns True if file size is within limits\n */\nexport function isFileSizeValid(\n fileSize: number,\n maxSize?: number,\n minSize?: number,\n): boolean {\n if (maxSize !== undefined && fileSize > maxSize) {\n return false;\n }\n\n if (minSize !== undefined && fileSize < minSize) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Get file extension\n * @param fileName - File name\n * @returns File extension without dot (e.g., 'pdf' for 'document.pdf')\n */\nexport function getFileExtension(fileName: string): string {\n const lastDot = fileName.lastIndexOf(\".\");\n if (lastDot === -1) return \"\";\n return fileName.slice(lastDot + 1).toLowerCase();\n}\n\n/**\n * Get file name without extension\n * @param fileName - File name\n * @returns File name without extension\n */\nexport function getFileNameWithoutExtension(fileName: string): string {\n const lastDot = fileName.lastIndexOf(\".\");\n if (lastDot === -1) return fileName;\n return fileName.slice(0, lastDot);\n}\n\n/**\n * Check if file is an image\n * @param fileName - File name\n * @returns True if file is an image\n */\nexport function isImageFile(fileName: string): boolean {\n const imageExtensions = [\n \".jpg\",\n \".jpeg\",\n \".png\",\n \".gif\",\n \".bmp\",\n \".webp\",\n \".svg\",\n ];\n const ext = fileName.toLowerCase().slice(fileName.lastIndexOf(\".\"));\n return imageExtensions.includes(ext);\n}\n\n/**\n * Check if file is a video\n * @param fileName - File name\n * @returns True if file is a video\n */\nexport function isVideoFile(fileName: string): boolean {\n const videoExtensions = [\n \".mp4\",\n \".avi\",\n \".mov\",\n \".wmv\",\n \".flv\",\n \".mkv\",\n \".webm\",\n ];\n const ext = fileName.toLowerCase().slice(fileName.lastIndexOf(\".\"));\n return videoExtensions.includes(ext);\n}\n\n/**\n * Check if file is a document\n * @param fileName - File name\n * @returns True if file is a document\n */\nexport function isDocumentFile(fileName: string): boolean {\n const docExtensions = [\n \".pdf\",\n \".doc\",\n \".docx\",\n \".xls\",\n \".xlsx\",\n \".ppt\",\n \".pptx\",\n \".txt\",\n \".csv\",\n ];\n const ext = fileName.toLowerCase().slice(fileName.lastIndexOf(\".\"));\n return docExtensions.includes(ext);\n}\n","/**\n * Permission utility functions for React Native uploads\n * Handles camera, gallery, and file access permissions\n */\n\n/**\n * Permission types\n */\nexport enum PermissionType {\n CAMERA = \"CAMERA\",\n PHOTO_LIBRARY = \"PHOTO_LIBRARY\",\n WRITE_STORAGE = \"WRITE_STORAGE\",\n READ_STORAGE = \"READ_STORAGE\",\n}\n\n/**\n * Permission status\n */\nexport enum PermissionStatus {\n GRANTED = \"granted\",\n DENIED = \"denied\",\n NOT_DETERMINED = \"not_determined\",\n RESTRICTED = \"restricted\",\n}\n\n/**\n * Request camera permission\n * This is primarily used to check if we should attempt camera operations\n * Actual permission requests are handled by the file system providers\n *\n * @returns Promise resolving to true if permission is granted or already granted\n */\nexport async function requestCameraPermission(): Promise<boolean> {\n try {\n // Permission requests are handled by the file system provider implementations\n // This function serves as a placeholder for app-level permission handling\n console.log(\n \"Camera permission requested (handled by file system provider)\",\n );\n return true;\n } catch (error) {\n console.error(\"Failed to request camera permission:\", error);\n return false;\n }\n}\n\n/**\n * Request photo library permission\n * @returns Promise resolving to true if permission is granted\n */\nexport async function requestPhotoLibraryPermission(): Promise<boolean> {\n try {\n console.log(\n \"Photo library permission requested (handled by file system provider)\",\n );\n return true;\n } catch (error) {\n console.error(\"Failed to request photo library permission:\", error);\n return false;\n }\n}\n\n/**\n * Request storage read permission\n * @returns Promise resolving to true if permission is granted\n */\nexport async function requestStorageReadPermission(): Promise<boolean> {\n try {\n console.log(\n \"Storage read permission requested (handled by file system provider)\",\n );\n return true;\n } catch (error) {\n console.error(\"Failed to request storage read permission:\", error);\n return false;\n }\n}\n\n/**\n * Request storage write permission\n * @returns Promise resolving to true if permission is granted\n */\nexport async function requestStorageWritePermission(): Promise<boolean> {\n try {\n console.log(\n \"Storage write permission requested (handled by file system provider)\",\n );\n return true;\n } catch (error) {\n console.error(\"Failed to request storage write permission:\", error);\n return false;\n }\n}\n\n/**\n * Request multiple permissions at once\n * @param permissions - Array of permission types to request\n * @returns Promise resolving to true if all permissions are granted\n */\nexport async function requestPermissions(\n permissions: PermissionType[],\n): Promise<boolean> {\n try {\n const results = await Promise.all(\n permissions.map(async (permission) => {\n switch (permission) {\n case PermissionType.CAMERA:\n return requestCameraPermission();\n case PermissionType.PHOTO_LIBRARY:\n return requestPhotoLibraryPermission();\n case PermissionType.READ_STORAGE:\n return requestStorageReadPermission();\n case PermissionType.WRITE_STORAGE:\n return requestStorageWritePermission();\n default:\n return false;\n }\n }),\n );\n\n return results.every((result) => result);\n } catch (error) {\n console.error(\"Failed to request permissions:\", error);\n return false;\n }\n}\n\n/**\n * Check if all required permissions are granted\n * @param permissions - Array of permission types to check\n * @returns Promise resolving to true if all permissions are granted\n */\nexport async function hasPermissions(\n _permissions: PermissionType[],\n): Promise<boolean> {\n try {\n // In React Native, permission checking is typically handled by the platform\n // This is a placeholder that assumes permissions will be handled by the file system provider\n return true;\n } catch (error) {\n console.error(\"Failed to check permissions:\", error);\n return false;\n }\n}\n\n/**\n * Get permission status\n * @param permission - Permission type to check\n * @returns Promise resolving to permission status\n */\nexport async function getPermissionStatus(\n _permission: PermissionType,\n): Promise<PermissionStatus> {\n try {\n // This is a placeholder implementation\n // Real implementation would use platform-specific APIs\n return PermissionStatus.GRANTED;\n } catch (error) {\n console.error(\"Failed to get permission status:\", error);\n return PermissionStatus.DENIED;\n }\n}\n\n/**\n * Open app settings to request permissions\n * Guides user to app settings where they can manually enable permissions\n */\nexport function openAppSettings(): void {\n try {\n // This would typically use react-native-app-settings or similar\n console.log(\n \"Opening app settings (requires react-native-app-settings or platform implementation)\",\n );\n } catch (error) {\n console.error(\"Failed to open app settings:\", error);\n }\n}\n","/**\n * URI utility functions for React Native file handling\n */\n\n/**\n * Extract file name from URI\n * @param uri - File URI\n * @returns File name extracted from URI\n */\nexport function getFileNameFromUri(uri: string): string {\n try {\n // Handle different URI formats\n if (uri.startsWith(\"file://\")) {\n // File URI format\n const path = uri.replace(\"file://\", \"\");\n return path.split(\"/\").pop() || \"file\";\n }\n\n if (uri.startsWith(\"content://\")) {\n // Content URI format (Android)\n const parts = uri.split(\"/\");\n return parts[parts.length - 1] || \"file\";\n }\n\n // Assume it's a path or other format\n const parts = uri.split(\"/\");\n return parts[parts.length - 1] || \"file\";\n } catch {\n return \"file\";\n }\n}\n\n/**\n * Convert file path to file URI\n * @param filePath - File path\n * @returns File URI\n */\nexport function pathToUri(filePath: string): string {\n if (filePath.startsWith(\"file://\")) {\n return filePath;\n }\n\n if (filePath.startsWith(\"content://\")) {\n return filePath;\n }\n\n // Convert to file URI\n return `file://${filePath}`;\n}\n\n/**\n * Convert file URI to file path\n * @param uri - File URI\n * @returns File path\n */\nexport function uriToPath(uri: string): string {\n if (uri.startsWith(\"file://\")) {\n return uri.replace(\"file://\", \"\");\n }\n\n if (uri.startsWith(\"content://\")) {\n // Content URIs cannot be converted to paths directly\n return uri;\n }\n\n return uri;\n}\n\n/**\n * Get directory from URI\n * @param uri - File URI\n * @returns Directory path\n */\nexport function getDirectoryFromUri(uri: string): string {\n try {\n const path = uriToPath(uri);\n const parts = path.split(\"/\");\n parts.pop(); // Remove file name\n return parts.join(\"/\");\n } catch {\n return \"\";\n }\n}\n\n/**\n * Check if URI is a content URI (Android specific)\n * @param uri - URI to check\n * @returns True if URI is a content URI\n */\nexport function isContentUri(uri: string): boolean {\n return uri.startsWith(\"content://\");\n}\n\n/**\n * Check if URI is a file URI\n * @param uri - URI to check\n * @returns True if URI is a file URI\n */\nexport function isFileUri(uri: string): boolean {\n return uri.startsWith(\"file://\");\n}\n\n/**\n * Normalize URI for cross-platform compatibility\n * @param uri - URI to normalize\n * @returns Normalized URI\n */\nexport function normalizeUri(uri: string): string {\n // Remove duplicate slashes (but keep protocol slashes)\n return uri.replace(/([^:]\\/)\\/+/g, \"$1\");\n}\n\n/**\n * Get MIME type hint from URI\n * @param uri - File URI\n * @returns MIME type hint based on file extension\n */\nexport function getMimeTypeFromUri(uri: string): string {\n const fileName = getFileNameFromUri(uri);\n\n const mimeTypes: Record<string, string> = {\n // Images\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".png\": \"image/png\",\n \".gif\": \"image/gif\",\n \".bmp\": \"image/bmp\",\n \".webp\": \"image/webp\",\n\n // Videos\n \".mp4\": \"video/mp4\",\n \".mov\": \"video/quicktime\",\n \".avi\": \"video/x-msvideo\",\n\n // Audio\n \".mp3\": \"audio/mpeg\",\n \".wav\": \"audio/wav\",\n \".aac\": \"audio/aac\",\n\n // Documents\n \".pdf\": \"application/pdf\",\n \".txt\": \"text/plain\",\n \".json\": \"application/json\",\n };\n\n const ext = fileName.toLowerCase().slice(fileName.lastIndexOf(\".\"));\n return mimeTypes[ext] || \"application/octet-stream\";\n}\n","import { ActivityIndicator, StyleSheet, Text, View } from \"react-native\";\nimport type { UploadState } from \"../hooks/use-upload\";\nimport { formatFileSize } from \"../utils\";\n\nexport interface UploadProgressProps {\n /** Upload state information */\n state: UploadState;\n /** Optional custom label */\n label?: string;\n}\n\n/**\n * Component to display upload progress with percentage, size, and speed\n */\nexport function UploadProgress({ state, label }: UploadProgressProps) {\n const getStatusColor = () => {\n switch (state.status) {\n case \"uploading\":\n return \"#007AFF\";\n case \"success\":\n return \"#34C759\";\n case \"error\":\n case \"aborted\":\n return \"#FF3B30\";\n default:\n return \"#999999\";\n }\n };\n\n const renderContent = () => {\n switch (state.status) {\n case \"idle\":\n return (\n <View style={styles.container}>\n <Text style={styles.label}>{label || \"Ready to upload\"}</Text>\n </View>\n );\n\n case \"uploading\":\n return (\n <View style={styles.container}>\n <View style={styles.headerRow}>\n <Text style={styles.label}>{label || \"Uploading\"}</Text>\n <Text style={styles.percentage}>{state.progress}%</Text>\n </View>\n\n {/* Progress bar */}\n <View style={styles.progressBarContainer}>\n <View\n style={[\n styles.progressBar,\n {\n width: `${state.progress}%`,\n backgroundColor: getStatusColor(),\n },\n ]}\n />\n </View>\n\n {/* Details row */}\n <View style={styles.detailsRow}>\n <Text style={styles.detail}>\n {formatFileSize(state.bytesUploaded)} /{\" \"}\n {formatFileSize(state.totalBytes || 0)}\n </Text>\n </View>\n </View>\n );\n\n case \"success\":\n return (\n <View style={styles.container}>\n <View style={styles.headerRow}>\n <Text style={[styles.label, { color: getStatusColor() }]}>\n {label || \"Upload complete\"}\n </Text>\n <Text style={[styles.percentage, { color: getStatusColor() }]}>\n ✓\n </Text>\n </View>\n <Text style={[styles.detail, { color: getStatusColor() }]}>\n {formatFileSize(state.totalBytes || 0)}\n </Text>\n </View>\n );\n\n case \"error\":\n return (\n <View style={styles.container}>\n <View style={styles.headerRow}>\n <Text style={[styles.label, { color: getStatusColor() }]}>\n {label || \"Upload failed\"}\n </Text>\n <Text style={[styles.percentage, { color: getStatusColor() }]}>\n ✕\n </Text>\n </View>\n {state.error && (\n <Text style={[styles.detail, { color: getStatusColor() }]}>\n {state.error.message}\n </Text>\n )}\n </View>\n );\n\n case \"aborted\":\n return (\n <View style={styles.container}>\n <Text style={[styles.label, { color: getStatusColor() }]}>\n {label || \"Upload cancelled\"}\n </Text>\n </View>\n );\n\n default:\n return null;\n }\n };\n\n return (\n <View\n style={[\n styles.wrapper,\n {\n borderLeftColor: getStatusColor(),\n },\n ]}\n >\n {state.status === \"uploading\" && (\n <ActivityIndicator\n size=\"small\"\n color={getStatusColor()}\n style={styles.spinner}\n />\n )}\n {renderContent()}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n wrapper: {\n flexDirection: \"row\",\n alignItems: \"flex-start\",\n paddingVertical: 8,\n paddingHorizontal: 12,\n borderLeftWidth: 4,\n backgroundColor: \"#f5f5f5\",\n borderRadius: 4,\n gap: 8,\n },\n spinner: {\n marginTop: 4,\n },\n container: {\n flex: 1,\n gap: 4,\n },\n headerRow: {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n },\n label: {\n fontSize: 14,\n fontWeight: \"600\",\n color: \"#333333\",\n flex: 1,\n },\n percentage: {\n fontSize: 14,\n fontWeight: \"600\",\n color: \"#007AFF\",\n minWidth: 36,\n textAlign: \"right\",\n },\n progressBarContainer: {\n height: 4,\n backgroundColor: \"#e0e0e0\",\n borderRadius: 2,\n overflow: \"hidden\",\n },\n progressBar: {\n height: \"100%\",\n borderRadius: 2,\n },\n detailsRow: {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n },\n detail: {\n fontSize: 12,\n color: \"#666666\",\n },\n});\n","import { type ReactNode, useEffect } from \"react\";\nimport {\n ActivityIndicator,\n Pressable,\n StyleSheet,\n Text,\n View,\n} from \"react-native\";\nimport { useCameraUpload } from \"../hooks\";\nimport type { UseCameraUploadOptions } from \"../types\";\nimport { UploadProgress } from \"./UploadProgress\";\n\nexport interface CameraUploadButtonProps {\n /** Options for camera upload */\n options?: UseCameraUploadOptions;\n /** Button label text */\n label?: string;\n /** Custom button content */\n children?: ReactNode;\n /** Callback when upload completes successfully */\n onSuccess?: (result: unknown) => void;\n /** Callback when upload fails */\n onError?: (error: Error) => void;\n /** Callback when upload is cancelled */\n onCancel?: () => void;\n /** Whether to show progress inline */\n showProgress?: boolean;\n}\n\n/**\n * Button component for camera capture and upload\n * Triggers camera on press and handles upload with progress display\n */\nexport function CameraUploadButton({\n options,\n label = \"Take Photo\",\n children,\n onSuccess,\n onError,\n onCancel,\n showProgress = true,\n}: CameraUploadButtonProps) {\n const { state, captureAndUpload } = useCameraUpload(options);\n\n const handlePress = async () => {\n try {\n await captureAndUpload();\n } catch (error) {\n if (error instanceof Error) {\n if (\n error.message.includes(\"cancelled\") ||\n error.message.includes(\"aborted\")\n ) {\n onCancel?.();\n } else {\n onError?.(error);\n }\n }\n }\n };\n\n const isLoading = state.status === \"uploading\";\n const isDisabled = isLoading || state.status === \"aborted\";\n\n useEffect(() => {\n if (state.status === \"success\" && state.result) {\n onSuccess?.(state.result);\n }\n }, [state.status, state.result, onSuccess]);\n\n useEffect(() => {\n if (state.status === \"error\" && state.error) {\n onError?.(state.error);\n }\n }, [state.status, state.error, onError]);\n\n return (\n <View style={styles.container}>\n <Pressable\n style={[styles.button, isDisabled && styles.buttonDisabled]}\n onPress={handlePress}\n disabled={isDisabled}\n >\n {isLoading && (\n <ActivityIndicator\n size=\"small\"\n color=\"#FFFFFF\"\n style={styles.spinner}\n />\n )}\n <Text style={styles.buttonText}>{children || label}</Text>\n </Pressable>\n {showProgress && state.status !== \"idle\" && (\n <View style={styles.progressContainer}>\n <UploadProgress state={state} label=\"Camera upload\" />\n </View>\n )}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n gap: 8,\n },\n button: {\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"center\",\n paddingVertical: 12,\n paddingHorizontal: 16,\n backgroundColor: \"#007AFF\",\n borderRadius: 8,\n gap: 8,\n },\n buttonDisabled: {\n opacity: 0.6,\n },\n buttonText: {\n fontSize: 16,\n fontWeight: \"600\",\n color: \"#FFFFFF\",\n },\n spinner: {\n marginRight: 4,\n },\n progressContainer: {\n marginTop: 4,\n },\n});\n","import { type ReactNode, useEffect } from \"react\";\nimport {\n ActivityIndicator,\n Pressable,\n StyleSheet,\n Text,\n View,\n} from \"react-native\";\nimport { useFileUpload } from \"../hooks\";\nimport type { UseFileUploadOptions } from \"../types\";\nimport { UploadProgress } from \"./UploadProgress\";\n\nexport interface FileUploadButtonProps {\n /** Options for file upload */\n options?: UseFileUploadOptions;\n /** Button label text */\n label?: string;\n /** Custom button content */\n children?: ReactNode;\n /** Callback when upload completes successfully */\n onSuccess?: (result: unknown) => void;\n /** Callback when upload fails */\n onError?: (error: Error) => void;\n /** Callback when upload is cancelled */\n onCancel?: () => void;\n /** Whether to show progress inline */\n showProgress?: boolean;\n}\n\n/**\n * Button component for document/file selection and upload\n * Generic file picker with progress display\n */\nexport function FileUploadButton({\n options,\n label = \"Choose File\",\n children,\n onSuccess,\n onError,\n onCancel,\n showProgress = true,\n}: FileUploadButtonProps) {\n const { state, pickAndUpload } = useFileUpload(options);\n\n const handlePress = async () => {\n try {\n await pickAndUpload();\n } catch (error) {\n if (error instanceof Error) {\n if (\n error.message.includes(\"cancelled\") ||\n error.message.includes(\"aborted\")\n ) {\n onCancel?.();\n } else {\n onError?.(error);\n }\n }\n }\n };\n\n const isLoading = state.status === \"uploading\";\n const isDisabled = isLoading || state.status === \"aborted\";\n\n useEffect(() => {\n if (state.status === \"success\" && state.result) {\n onSuccess?.(state.result);\n }\n }, [state.status, state.result, onSuccess]);\n\n useEffect(() => {\n if (state.status === \"error\" && state.error) {\n onError?.(state.error);\n }\n }, [state.status, state.error, onError]);\n\n return (\n <View style={styles.container}>\n <Pressable\n style={[styles.button, isDisabled && styles.buttonDisabled]}\n onPress={handlePress}\n disabled={isDisabled}\n >\n {isLoading && (\n <ActivityIndicator\n size=\"small\"\n color=\"#FFFFFF\"\n style={styles.spinner}\n />\n )}\n <Text style={styles.buttonText}>{children || label}</Text>\n </Pressable>\n {showProgress && state.status !== \"idle\" && (\n <View style={styles.progressContainer}>\n <UploadProgress state={state} label=\"File upload\" />\n </View>\n )}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n gap: 8,\n },\n button: {\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"center\",\n paddingVertical: 12,\n paddingHorizontal: 16,\n backgroundColor: \"#FF9500\",\n borderRadius: 8,\n gap: 8,\n },\n buttonDisabled: {\n opacity: 0.6,\n },\n buttonText: {\n fontSize: 16,\n fontWeight: \"600\",\n color: \"#FFFFFF\",\n },\n spinner: {\n marginRight: 4,\n },\n progressContainer: {\n marginTop: 4,\n },\n});\n","import React, { type ReactNode } from \"react\";\nimport {\n ActivityIndicator,\n FlatList,\n Pressable,\n StyleSheet,\n Text,\n View,\n} from \"react-native\";\nimport { useGalleryUpload } from \"../hooks\";\nimport type { UseGalleryUploadOptions } from \"../types\";\nimport { UploadProgress } from \"./UploadProgress\";\n\nexport interface GalleryUploadButtonProps {\n /** Options for gallery upload */\n options?: UseGalleryUploadOptions;\n /** Button label text */\n label?: string;\n /** Custom button content */\n children?: ReactNode;\n /** Callback when all uploads complete successfully */\n onSuccess?: (results: unknown[]) => void;\n /** Callback when any upload fails */\n onError?: (error: Error) => void;\n /** Callback when upload is cancelled */\n onCancel?: () => void;\n /** Whether to show individual progress for each file */\n showProgress?: boolean;\n}\n\n/**\n * Button component for gallery selection and batch upload\n * Triggers gallery picker on press and handles concurrent uploads\n */\nexport function GalleryUploadButton({\n options,\n label = \"Select from Gallery\",\n children,\n onSuccess,\n onError,\n onCancel,\n showProgress = true,\n}: GalleryUploadButtonProps) {\n const { state, selectAndUpload } = useGalleryUpload(options);\n\n const handlePress = async () => {\n try {\n await selectAndUpload();\n } catch (error) {\n if (error instanceof Error) {\n if (\n error.message.includes(\"cancelled\") ||\n error.message.includes(\"aborted\")\n ) {\n onCancel?.();\n } else {\n onError?.(error);\n }\n }\n }\n };\n\n const isLoading = state.items.some((item) => item.status === \"uploading\");\n const hasItems = state.items.length > 0;\n const allComplete =\n hasItems &&\n state.items.every(\n (item) => item.status !== \"uploading\" && item.status !== \"idle\",\n );\n\n React.useEffect(() => {\n if (allComplete) {\n const results = state.items\n .filter((item) => item.status === \"success\")\n .map((item) => item.result);\n if (results.length > 0) {\n onSuccess?.(results);\n }\n }\n }, [allComplete, state.items, onSuccess]);\n\n React.useEffect(() => {\n const errors = state.items.filter((item) => item.status === \"error\");\n const firstError = errors[0]?.error;\n if (firstError) {\n onError?.(firstError);\n }\n }, [state.items, onError]);\n\n const renderItem = ({ item }: { item: (typeof state.items)[0] }) => (\n <View key={item.id} style={styles.itemContainer}>\n <UploadProgress\n state={{\n status: item.status,\n progress: item.progress,\n bytesUploaded: item.bytesUploaded,\n totalBytes: item.totalBytes,\n error: item.error,\n result: item.result,\n }}\n label={item.file.data.name}\n />\n </View>\n );\n\n return (\n <View style={styles.container}>\n <Pressable\n style={[styles.button, isLoading && styles.buttonDisabled]}\n onPress={handlePress}\n disabled={isLoading}\n >\n {isLoading && (\n <ActivityIndicator\n size=\"small\"\n color=\"#FFFFFF\"\n style={styles.spinner}\n />\n )}\n <Text style={styles.buttonText}>\n {children || label}\n {hasItems && ` (${state.items.length})`}\n </Text>\n </Pressable>\n\n {hasItems && (\n <View style={styles.statsContainer}>\n <Text style={styles.statsText}>\n Progress: {state.items.filter((i) => i.status === \"success\").length}\n /{state.items.length} uploaded\n </Text>\n <Text style={styles.statsText}>Overall: {state.totalProgress}%</Text>\n </View>\n )}\n\n {showProgress && hasItems && (\n <FlatList\n scrollEnabled={false}\n data={state.items}\n renderItem={renderItem}\n keyExtractor={(item) => item.id}\n style={styles.listContainer}\n contentContainerStyle={styles.listContent}\n ItemSeparatorComponent={() => <View style={styles.separator} />}\n />\n )}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n gap: 8,\n },\n button: {\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"center\",\n paddingVertical: 12,\n paddingHorizontal: 16,\n backgroundColor: \"#34C759\",\n borderRadius: 8,\n gap: 8,\n },\n buttonDisabled: {\n opacity: 0.6,\n },\n buttonText: {\n fontSize: 16,\n fontWeight: \"600\",\n color: \"#FFFFFF\",\n },\n spinner: {\n marginRight: 4,\n },\n statsContainer: {\n paddingVertical: 8,\n paddingHorizontal: 12,\n backgroundColor: \"#f5f5f5\",\n borderRadius: 4,\n gap: 4,\n },\n statsText: {\n fontSize: 12,\n color: \"#666666\",\n },\n listContainer: {\n maxHeight: 400,\n },\n listContent: {\n gap: 8,\n },\n itemContainer: {\n paddingHorizontal: 0,\n },\n separator: {\n height: 4,\n },\n});\n","import { FlatList, Pressable, StyleSheet, Text, View } from \"react-native\";\nimport type { UploadItem } from \"../types\";\nimport { UploadProgress } from \"./UploadProgress\";\n\nexport interface UploadListProps {\n /** List of upload items to display */\n items: UploadItem[];\n /** Callback when remove item is pressed */\n onRemove?: (id: string) => void;\n /** Callback when item is pressed */\n onItemPress?: (item: UploadItem) => void;\n /** Whether to show remove button */\n showRemoveButton?: boolean;\n}\n\n/**\n * Component to display a list of upload items with individual progress\n * Shows status indicators and allows removal of items\n */\nexport function UploadList({\n items,\n onRemove,\n onItemPress,\n showRemoveButton = true,\n}: UploadListProps) {\n const renderItem = ({ item }: { item: UploadItem }) => (\n <Pressable\n style={[\n styles.itemContainer,\n { borderLeftColor: getStatusColor(item.progress.state) },\n ]}\n onPress={() => onItemPress?.(item)}\n >\n <View style={styles.itemContent}>\n {item.file.status === \"success\" && (\n <View style={styles.itemHeader}>\n <Text style={styles.fileName} numberOfLines={1}>\n {item.file.data.name}\n </Text>\n <Text style={styles.fileSize}>\n {getFileSizeDisplay(item.file.data.size)}\n </Text>\n </View>\n )}\n {item.file.status === \"error\" && (\n <Text style={styles.errorText}>{item.progress.error?.message}</Text>\n )}\n <View style={styles.progressWrapper}>\n <UploadProgress\n state={{\n status:\n item.progress.state === \"pending\"\n ? \"idle\"\n : item.progress.state === \"cancelled\"\n ? \"aborted\"\n : item.progress.state,\n progress: item.progress.progress,\n bytesUploaded: item.progress.uploadedBytes,\n totalBytes: item.progress.totalBytes,\n error: item.progress.error || null,\n result: (item.result as any) || null,\n }}\n />\n </View>\n </View>\n {showRemoveButton &&\n item.progress.state !== \"uploading\" &&\n item.progress.state !== \"pending\" && (\n <Pressable\n style={styles.removeButton}\n onPress={() => onRemove?.(item.id)}\n hitSlop={{ top: 8, right: 8, bottom: 8, left: 8 }}\n >\n <Text style={styles.removeButtonText}>✕</Text>\n </Pressable>\n )}\n </Pressable>\n );\n\n if (items.length === 0) {\n return (\n <View style={styles.emptyContainer}>\n <Text style={styles.emptyText}>No uploads</Text>\n </View>\n );\n }\n\n return (\n <View style={styles.container}>\n <View style={styles.headerRow}>\n <Text style={styles.headerText}>Uploads ({items.length})</Text>\n <Text style={styles.headerSubtext}>\n {items.filter((i) => i.progress.state === \"success\").length} complete\n </Text>\n </View>\n <FlatList\n scrollEnabled={false}\n data={items}\n renderItem={renderItem}\n keyExtractor={(item) => item.id}\n ItemSeparatorComponent={() => <View style={styles.separator} />}\n contentContainerStyle={styles.listContent}\n />\n </View>\n );\n}\n\n// Helper functions\nfunction getStatusColor(state: string): string {\n switch (state) {\n case \"success\":\n return \"#34C759\";\n case \"error\":\n case \"cancelled\":\n return \"#FF3B30\";\n case \"uploading\":\n case \"pending\":\n return \"#007AFF\";\n default:\n return \"#999999\";\n }\n}\n\nfunction getFileSizeDisplay(bytes: number): string {\n if (bytes === 0) return \"0 B\";\n const k = 1024;\n const sizes = [\"B\", \"KB\", \"MB\", \"GB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${Math.round((bytes / k ** i) * 10) / 10} ${sizes[i]}`;\n}\n\nconst styles = StyleSheet.create({\n container: {\n gap: 8,\n },\n headerRow: {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n paddingHorizontal: 12,\n paddingVertical: 8,\n backgroundColor: \"#f9f9f9\",\n borderRadius: 4,\n },\n headerText: {\n fontSize: 16,\n fontWeight: \"600\",\n color: \"#333333\",\n },\n errorText: {\n fontSize: 14,\n color: \"#FF3B30\",\n },\n headerSubtext: {\n fontSize: 14,\n color: \"#666666\",\n },\n listContent: {\n gap: 8,\n },\n itemContainer: {\n flexDirection: \"row\",\n alignItems: \"center\",\n paddingVertical: 8,\n paddingHorizontal: 12,\n borderLeftWidth: 4,\n backgroundColor: \"#f5f5f5\",\n borderRadius: 4,\n gap: 8,\n },\n itemContent: {\n flex: 1,\n gap: 6,\n },\n itemHeader: {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n },\n fileName: {\n fontSize: 14,\n fontWeight: \"500\",\n color: \"#333333\",\n flex: 1,\n },\n fileSize: {\n fontSize: 12,\n color: \"#999999\",\n marginLeft: 8,\n },\n progressWrapper: {\n marginTop: 2,\n },\n removeButton: {\n width: 32,\n height: 32,\n justifyContent: \"center\",\n alignItems: \"center\",\n borderRadius: 16,\n backgroundColor: \"#FFE5E5\",\n },\n removeButtonText: {\n fontSize: 16,\n fontWeight: \"600\",\n color: \"#FF3B30\",\n },\n separator: {\n height: 4,\n },\n emptyContainer: {\n paddingVertical: 24,\n paddingHorizontal: 12,\n backgroundColor: \"#f5f5f5\",\n borderRadius: 4,\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n emptyText: {\n fontSize: 14,\n color: \"#999999\",\n fontStyle: \"italic\",\n },\n});\n"],"mappings":"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,UACjB,aAAc,EACf,CACD,WAAY,CACV,SAAU,GACV,WAAY,MACZ,MAAO,UACR,CACD,UAAW,CACT,SAAU,GACV,MAAO,UACR,CACD,cAAe,CACb,SAAU,GACV,MAAO,UACR,CACD,YAAa,CACX,IAAK,EACN,CACD,cAAe,CACb,cAAe,MACf,WAAY,SACZ,gBAAiB,EACjB,kBAAmB,GACnB,gBAAiB,EACjB,gBAAiB,UACjB,aAAc,EACd,IAAK,EACN,CACD,YAAa,CACX,KAAM,EACN,IAAK,EACN,CACD,WAAY,CACV,cAAe,MACf,eAAgB,gBAChB,WAAY,SACb,CACD,SAAU,CACR,SAAU,GACV,WAAY,MACZ,MAAO,UACP,KAAM,EACP,CACD,SAAU,CACR,SAAU,GACV,MAAO,UACP,WAAY,EACb,CACD,gBAAiB,CACf,UAAW,EACZ,CACD,aAAc,CACZ,MAAO,GACP,OAAQ,GACR,eAAgB,SAChB,WAAY,SACZ,aAAc,GACd,gBAAiB,UAClB,CACD,iBAAkB,CAChB,SAAU,GACV,WAAY,MACZ,MAAO,UACR,CACD,UAAW,CACT,OAAQ,EACT,CACD,eAAgB,CACd,gBAAiB,GACjB,kBAAmB,GACnB,gBAAiB,UACjB,aAAc,EACd,WAAY,SACZ,eAAgB,SACjB,CACD,UAAW,CACT,SAAU,GACV,MAAO,UACP,UAAW,SACZ,CACF,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["initialState: UploadState","initialState","initialState: FlowUploadState","initialState","initialState: MultiUploadState","newItems: UploadItemState[]","result: FilePickResult","parts","getStatusColor","styles","styles","styles","styles"],"sources":["../src/hooks/uploadista-context.ts","../src/hooks/use-uploadista-context.ts","../src/hooks/use-upload.ts","../src/hooks/use-camera-upload.ts","../src/hooks/use-file-upload.ts","../src/hooks/use-flow-upload.ts","../src/hooks/use-multi-upload.ts","../src/hooks/use-gallery-upload.ts","../src/hooks/use-upload-metrics.ts","../src/utils/fileHelpers.ts","../src/utils/permissions.ts","../src/utils/uriHelpers.ts","../src/components/UploadProgress.tsx","../src/components/CameraUploadButton.tsx","../src/components/FileUploadButton.tsx","../src/components/GalleryUploadButton.tsx","../src/components/UploadList.tsx"],"sourcesContent":["import type { UploadistaEvent } from \"@uploadista/client-core\";\nimport { createContext } from \"react\";\nimport type { FileSystemProvider } from \"../types\";\nimport type { UseUploadistaClientReturn } from \"./use-uploadista-client\";\n\nexport interface UploadistaContextType extends UseUploadistaClientReturn {\n fileSystemProvider: FileSystemProvider;\n /**\n * Subscribe to events (used internally by hooks)\n * @internal\n */\n subscribeToEvents: (handler: (event: UploadistaEvent) => void) => () => void;\n}\n\nexport const UploadistaContext = createContext<\n UploadistaContextType | undefined\n>(undefined);\n","import { useContext } from \"react\";\nimport { UploadistaContext } from \"./uploadista-context\";\n\n/**\n * Hook to access the Uploadista client instance\n * Must be used within an UploadistaProvider\n * @throws Error if used outside of UploadistaProvider\n * @returns The Uploadista client and file system provider\n */\nexport function useUploadistaContext() {\n const context = useContext(UploadistaContext);\n\n if (!context) {\n throw new Error(\n \"useUploadistaClient must be used within an UploadistaProvider\",\n );\n }\n\n return context;\n}\n","import type { UploadistaEvent } from \"@uploadista/client-core\";\nimport type { UploadFile } from \"@uploadista/core/types\";\nimport { UploadEventType } from \"@uploadista/core/types\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { FilePickResult } from \"../types\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\nexport type UploadStatus =\n | \"idle\"\n | \"uploading\"\n | \"success\"\n | \"error\"\n | \"aborted\";\n\nexport interface UploadState {\n status: UploadStatus;\n progress: number;\n bytesUploaded: number;\n totalBytes: number | null;\n error: Error | null;\n result: UploadFile | null;\n}\n\nexport interface UseUploadOptions {\n /**\n * Upload metadata to attach to the file\n */\n metadata?: Record<string, string>;\n\n /**\n * Whether to defer the upload size calculation\n */\n uploadLengthDeferred?: boolean;\n\n /**\n * Manual upload size override\n */\n uploadSize?: number;\n\n /**\n * Called when upload progress updates\n */\n onProgress?: (\n progress: number,\n bytesUploaded: number,\n totalBytes: number | null,\n ) => void;\n\n /**\n * Called when a chunk completes\n */\n onChunkComplete?: (\n chunkSize: number,\n bytesAccepted: number,\n bytesTotal: number | null,\n ) => void;\n\n /**\n * Called when upload succeeds\n */\n onSuccess?: (result: UploadFile) => void;\n\n /**\n * Called when upload fails\n */\n onError?: (error: Error) => void;\n\n /**\n * Called when upload is aborted\n */\n onAbort?: () => void;\n\n /**\n * Custom retry logic\n */\n onShouldRetry?: (error: Error, retryAttempt: number) => boolean;\n}\n\nexport interface UseUploadReturn {\n /**\n * Current upload state\n */\n state: UploadState;\n\n /**\n * Start uploading a file from a file pick result\n */\n upload: (file: FilePickResult) => Promise<void>;\n\n /**\n * Abort the current upload\n */\n abort: () => void;\n\n /**\n * Reset the upload state to idle\n */\n reset: () => void;\n\n /**\n * Retry the last failed upload\n */\n retry: () => void;\n\n /**\n * Whether an upload is currently active\n */\n isUploading: boolean;\n\n /**\n * Whether the upload can be retried\n */\n canRetry: boolean;\n}\n\nconst initialState: UploadState = {\n status: \"idle\",\n progress: 0,\n bytesUploaded: 0,\n totalBytes: null,\n error: null,\n result: null,\n};\n\n/**\n * React hook for managing individual file uploads with full state management.\n * Provides upload progress tracking, error handling, abort functionality, and retry logic.\n *\n * Must be used within an UploadistaProvider.\n *\n * @param options - Upload configuration and event handlers\n * @returns Upload state and control methods\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const upload = useUpload({\n * onSuccess: (result) => console.log('Upload complete:', result),\n * onError: (error) => console.error('Upload failed:', error),\n * onProgress: (progress) => console.log('Progress:', progress + '%'),\n * });\n *\n * const handlePickFile = async () => {\n * const file = await fileSystemProvider.pickDocument();\n * if (file) {\n * await upload.upload(file);\n * }\n * };\n *\n * return (\n * <View>\n * <Button title=\"Pick File\" onPress={handlePickFile} />\n * {upload.isUploading && <Text>Progress: {upload.state.progress}%</Text>}\n * {upload.state.error && <Text>Error: {upload.state.error.message}</Text>}\n * {upload.canRetry && <Button title=\"Retry\" onPress={upload.retry} />}\n * <Button title=\"Abort\" onPress={upload.abort} disabled={!upload.isUploading} />\n * </View>\n * );\n * }\n * ```\n */\nexport function useUpload(options: UseUploadOptions = {}): UseUploadReturn {\n const { client, fileSystemProvider, subscribeToEvents } =\n useUploadistaContext();\n const [state, setState] = useState<UploadState>(initialState);\n const abortControllerRef = useRef<{ abort: () => void } | null>(null);\n const lastFileRef = useRef<FilePickResult | null>(null);\n const currentUploadIdRef = useRef<string | null>(null);\n\n const updateState = useCallback((update: Partial<UploadState>) => {\n setState((prev) => ({ ...prev, ...update }));\n }, []);\n\n const reset = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n abortControllerRef.current = null;\n }\n setState(initialState);\n lastFileRef.current = null;\n currentUploadIdRef.current = null;\n }, []);\n\n const abort = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n abortControllerRef.current = null;\n }\n\n updateState({\n status: \"aborted\",\n });\n\n options.onAbort?.();\n }, [options, updateState]);\n\n const upload = useCallback(\n async (file: FilePickResult) => {\n // Handle cancelled picker\n if (file.status === \"cancelled\") {\n return;\n }\n\n // Handle picker error\n if (file.status === \"error\") {\n updateState({\n status: \"error\",\n error: file.error,\n });\n options.onError?.(file.error);\n return;\n }\n\n // Reset any previous state\n setState({\n ...initialState,\n status: \"uploading\",\n totalBytes: file.data.size,\n });\n\n lastFileRef.current = file;\n\n try {\n // Read file content\n const fileContent = await fileSystemProvider.readFile(file.data.uri);\n\n // Create a Blob from the file content\n // Convert ArrayBuffer to Uint8Array for better compatibility\n const data =\n fileContent instanceof ArrayBuffer\n ? new Uint8Array(fileContent)\n : fileContent;\n // Note: Using any cast here because React Native Blob accepts BufferSource\n // but TypeScript's lib.dom.d.ts Blob type doesn't include it\n // biome-ignore lint/suspicious/noExplicitAny: React Native Blob accepts BufferSource\n const blob = new Blob([data as any], {\n type: file.data.mimeType || \"application/octet-stream\",\n // biome-ignore lint/suspicious/noExplicitAny: BlobPropertyBag type differs by platform\n } as any);\n\n // use the Blob (for React Native)\n const uploadInput = blob;\n\n // Start the upload using the client\n const uploadPromise = client.upload(uploadInput, {\n metadata: options.metadata,\n uploadLengthDeferred: options.uploadLengthDeferred,\n uploadSize: options.uploadSize,\n\n onStart: ({ uploadId }) => {\n currentUploadIdRef.current = uploadId;\n },\n\n onProgress: (\n _uploadId: string,\n bytesUploaded: number,\n totalBytes: number | null,\n ) => {\n const progress = totalBytes\n ? Math.round((bytesUploaded / totalBytes) * 100)\n : 0;\n\n updateState({\n progress,\n bytesUploaded,\n totalBytes,\n });\n\n options.onProgress?.(progress, bytesUploaded, totalBytes);\n },\n\n onChunkComplete: (\n chunkSize: number,\n bytesAccepted: number,\n bytesTotal: number | null,\n ) => {\n options.onChunkComplete?.(chunkSize, bytesAccepted, bytesTotal);\n },\n\n onSuccess: (result: UploadFile) => {\n updateState({\n status: \"success\",\n result,\n progress: 100,\n bytesUploaded: result.size || 0,\n totalBytes: result.size || null,\n });\n\n options.onSuccess?.(result);\n abortControllerRef.current = null;\n },\n\n onError: (error: Error) => {\n updateState({\n status: \"error\",\n error,\n });\n\n options.onError?.(error);\n abortControllerRef.current = null;\n },\n\n onShouldRetry: options.onShouldRetry,\n });\n\n // Handle the promise to get the abort controller\n const controller = await uploadPromise;\n abortControllerRef.current = controller;\n } catch (error) {\n updateState({\n status: \"error\",\n error: error as Error,\n });\n\n options.onError?.(error as Error);\n abortControllerRef.current = null;\n }\n },\n [client, fileSystemProvider, options, updateState],\n );\n\n const retry = useCallback(() => {\n if (\n lastFileRef.current &&\n (state.status === \"error\" || state.status === \"aborted\")\n ) {\n upload(lastFileRef.current);\n }\n }, [upload, state.status]);\n\n // Subscribe to events from context (WebSocket events)\n useEffect(() => {\n const unsubscribe = subscribeToEvents((event: UploadistaEvent) => {\n // Handle upload progress events\n const uploadEvent = event as {\n type: string;\n data?: { id: string; progress: number; total: number };\n };\n\n if (\n uploadEvent.type === UploadEventType.UPLOAD_PROGRESS &&\n uploadEvent.data\n ) {\n const {\n id: uploadId,\n progress: bytesUploaded,\n total: totalBytes,\n } = uploadEvent.data;\n\n if (uploadId !== currentUploadIdRef.current) {\n return;\n }\n\n // Update state for this upload\n const progress = totalBytes\n ? Math.round((bytesUploaded / totalBytes) * 100)\n : 0;\n\n setState((prev) => {\n // Only update if we're currently uploading\n if (prev.status === \"uploading\") {\n return {\n ...prev,\n progress,\n bytesUploaded,\n totalBytes,\n };\n }\n return prev;\n });\n\n options.onProgress?.(progress, bytesUploaded, totalBytes);\n }\n });\n\n return unsubscribe;\n }, [subscribeToEvents, options]);\n\n const isUploading = state.status === \"uploading\";\n const canRetry =\n (state.status === \"error\" || state.status === \"aborted\") &&\n lastFileRef.current !== null;\n\n return {\n state,\n upload,\n abort,\n reset,\n retry,\n isUploading,\n canRetry,\n };\n}\n","import { useCallback } from \"react\";\nimport type { UseCameraUploadOptions } from \"../types\";\nimport { useUpload } from \"./use-upload\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\n/**\n * Hook for capturing photos and uploading them\n * Handles camera permissions and capture flow\n * @param options - Camera upload configuration\n * @returns Upload state and camera capture/upload function\n */\nexport function useCameraUpload(options?: UseCameraUploadOptions) {\n const { fileSystemProvider } = useUploadistaContext();\n const uploadHook = useUpload({\n metadata: options?.metadata,\n onSuccess: options?.onSuccess,\n onError: options?.onError,\n onProgress: options?.onProgress,\n });\n\n // Capture and upload photo\n const captureAndUpload = useCallback(async () => {\n try {\n // Capture photo with camera\n const photo = await fileSystemProvider.pickCamera(options?.cameraOptions);\n\n // Upload captured photo\n await uploadHook.upload(photo);\n } catch (error) {\n console.error(\"Camera capture error:\", error);\n }\n }, [fileSystemProvider, options?.cameraOptions, uploadHook]);\n\n return {\n ...uploadHook,\n captureAndUpload,\n };\n}\n","import { useCallback } from \"react\";\nimport type { UseFileUploadOptions } from \"../types\";\nimport { useUpload } from \"./use-upload\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\n/**\n * Hook for selecting and uploading generic files (documents, etc.)\n * @param options - File upload configuration\n * @returns Upload state and file picker/upload function\n */\nexport function useFileUpload(options?: UseFileUploadOptions) {\n const { fileSystemProvider } = useUploadistaContext();\n const uploadHook = useUpload({\n metadata: options?.metadata,\n onSuccess: options?.onSuccess,\n onError: options?.onError,\n onProgress: options?.onProgress,\n });\n\n // Pick and upload file\n const pickAndUpload = useCallback(async () => {\n try {\n // Pick file\n const file = await fileSystemProvider.pickDocument({\n allowedTypes: options?.allowedTypes,\n });\n\n // Upload file\n await uploadHook.upload(file);\n } catch (error) {\n console.error(\"File selection error:\", error);\n throw error;\n }\n }, [fileSystemProvider, options?.allowedTypes, uploadHook]);\n\n return {\n ...uploadHook,\n pickAndUpload,\n };\n}\n","import type { UploadFile } from \"@uploadista/core/types\";\nimport { useCallback, useRef, useState } from \"react\";\nimport type { FilePickResult, UseFlowUploadOptions } from \"../types\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\nexport type FlowUploadStatus =\n | \"idle\"\n | \"uploading\"\n | \"processing\"\n | \"success\"\n | \"error\"\n | \"aborted\";\n\nexport interface FlowUploadState {\n status: FlowUploadStatus;\n progress: number;\n bytesUploaded: number;\n totalBytes: number | null;\n jobId: string | null;\n error: Error | null;\n result: unknown | null;\n}\n\nconst initialState: FlowUploadState = {\n status: \"idle\",\n progress: 0,\n bytesUploaded: 0,\n totalBytes: null,\n jobId: null,\n error: null,\n result: null,\n};\n\n/**\n * Hook for uploading files through a flow pipeline with full state management.\n * Provides upload progress tracking, flow execution monitoring, error handling, and abort functionality.\n *\n * Must be used within an UploadistaProvider.\n *\n * @param options - Flow upload configuration\n * @returns Flow upload state and control methods\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const flowUpload = useFlowUpload({\n * flowId: 'image-processing-flow',\n * storageId: 'my-storage',\n * onSuccess: (result) => console.log('Flow complete:', result),\n * onError: (error) => console.error('Flow failed:', error),\n * onProgress: (progress) => console.log('Progress:', progress + '%'),\n * });\n *\n * const handlePickFile = async () => {\n * const file = await fileSystemProvider.pickDocument();\n * if (file) {\n * await flowUpload.upload(file);\n * }\n * };\n *\n * return (\n * <View>\n * <Button title=\"Pick File\" onPress={handlePickFile} />\n * {flowUpload.isUploading && <Text>Progress: {flowUpload.state.progress}%</Text>}\n * {flowUpload.state.jobId && <Text>Job ID: {flowUpload.state.jobId}</Text>}\n * {flowUpload.state.error && <Text>Error: {flowUpload.state.error.message}</Text>}\n * <Button title=\"Abort\" onPress={flowUpload.abort} disabled={!flowUpload.isActive} />\n * </View>\n * );\n * }\n * ```\n */\nexport function useFlowUpload(options: UseFlowUploadOptions) {\n const { client, fileSystemProvider } = useUploadistaContext();\n const [state, setState] = useState<FlowUploadState>(initialState);\n const abortControllerRef = useRef<{ abort: () => void } | null>(null);\n const lastFileRef = useRef<FilePickResult | null>(null);\n\n const updateState = useCallback((update: Partial<FlowUploadState>) => {\n setState((prev) => ({ ...prev, ...update }));\n }, []);\n\n const reset = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n abortControllerRef.current = null;\n }\n setState(initialState);\n lastFileRef.current = null;\n }, []);\n\n const abort = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n abortControllerRef.current = null;\n }\n\n updateState({\n status: \"aborted\",\n });\n }, [updateState]);\n\n const upload = useCallback(\n async (file: FilePickResult) => {\n // Handle cancelled picker\n if (file.status === \"cancelled\") {\n return;\n }\n\n // Handle picker error\n if (file.status === \"error\") {\n updateState({\n status: \"error\",\n error: file.error,\n });\n options.onError?.(file.error);\n return;\n }\n\n // Reset any previous state\n setState({\n ...initialState,\n status: \"uploading\",\n totalBytes: file.data.size,\n });\n\n lastFileRef.current = file;\n\n try {\n // Read file content\n const fileContent = await fileSystemProvider.readFile(file.data.uri);\n\n // Create a Blob from the file content\n // Convert ArrayBuffer to Uint8Array for better compatibility\n const data =\n fileContent instanceof ArrayBuffer\n ? new Uint8Array(fileContent)\n : fileContent;\n // Note: Using any cast here because React Native Blob accepts BufferSource\n // but TypeScript's lib.dom.d.ts Blob type doesn't include it\n // biome-ignore lint/suspicious/noExplicitAny: React Native Blob accepts BufferSource\n const blob = new Blob([data as any], {\n type: file.data.mimeType || \"application/octet-stream\",\n // biome-ignore lint/suspicious/noExplicitAny: BlobPropertyBag type differs by platform\n } as any);\n\n // use the Blob (for React Native)\n const uploadInput = blob;\n\n // Start the flow upload using the client\n const uploadPromise = client.uploadWithFlow(\n uploadInput,\n {\n flowId: options.flowId,\n storageId: options.storageId,\n outputNodeId: options.outputNodeId,\n metadata: options.metadata as Record<string, string> | undefined,\n },\n {\n onJobStart: () => {\n updateState({\n status: \"processing\",\n });\n },\n\n onProgress: (\n _uploadId: string,\n bytesUploaded: number,\n totalBytes: number | null,\n ) => {\n const progress = totalBytes\n ? Math.round((bytesUploaded / totalBytes) * 100)\n : 0;\n\n updateState({\n progress,\n bytesUploaded,\n totalBytes,\n });\n\n options.onProgress?.(progress, bytesUploaded, totalBytes);\n },\n\n onChunkComplete: (\n chunkSize: number,\n bytesAccepted: number,\n bytesTotal: number | null,\n ) => {\n options.onChunkComplete?.(chunkSize, bytesAccepted, bytesTotal);\n },\n\n onSuccess: (result: UploadFile) => {\n updateState({\n status: \"success\",\n result,\n progress: 100,\n bytesUploaded: result.size || 0,\n totalBytes: result.size || null,\n });\n\n options.onSuccess?.(result);\n abortControllerRef.current = null;\n },\n\n onError: (error: Error) => {\n updateState({\n status: \"error\",\n error,\n });\n\n options.onError?.(error);\n abortControllerRef.current = null;\n },\n },\n );\n\n // Handle the promise to get the abort controller\n const controller = await uploadPromise;\n abortControllerRef.current = controller;\n } catch (error) {\n updateState({\n status: \"error\",\n error: error as Error,\n });\n\n options.onError?.(error as Error);\n abortControllerRef.current = null;\n }\n },\n [client, fileSystemProvider, options, updateState],\n );\n\n const retry = useCallback(() => {\n if (\n lastFileRef.current &&\n (state.status === \"error\" || state.status === \"aborted\")\n ) {\n upload(lastFileRef.current);\n }\n }, [upload, state.status]);\n\n const isActive =\n state.status === \"uploading\" || state.status === \"processing\";\n const canRetry =\n (state.status === \"error\" || state.status === \"aborted\") &&\n lastFileRef.current !== null;\n\n return {\n state,\n upload,\n abort,\n reset,\n retry,\n isActive,\n canRetry,\n };\n}\n","import type { UploadFile } from \"@uploadista/core/types\";\nimport { useCallback, useRef, useState } from \"react\";\nimport type { FilePickResult, UseMultiUploadOptions } from \"../types\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\nexport interface UploadItemState {\n id: string;\n file: Extract<FilePickResult, { status: \"success\" }>;\n status: \"idle\" | \"uploading\" | \"success\" | \"error\" | \"aborted\";\n progress: number;\n bytesUploaded: number;\n totalBytes: number;\n error: Error | null;\n result: UploadFile | null;\n}\n\nexport interface MultiUploadState {\n items: UploadItemState[];\n totalProgress: number;\n totalUploaded: number;\n totalBytes: number;\n activeCount: number;\n completedCount: number;\n failedCount: number;\n}\n\nconst initialState: MultiUploadState = {\n items: [],\n totalProgress: 0,\n totalUploaded: 0,\n totalBytes: 0,\n activeCount: 0,\n completedCount: 0,\n failedCount: 0,\n};\n\n/**\n * Hook for managing multiple concurrent file uploads with progress tracking.\n * Each file is uploaded independently using the core upload client.\n *\n * Must be used within an UploadistaProvider.\n *\n * @param options - Multi-upload configuration options\n * @returns Multi-upload state and control methods\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const multiUpload = useMultiUpload({\n * maxConcurrent: 3,\n * onSuccess: (result) => console.log('File uploaded:', result),\n * onError: (error) => console.error('Upload failed:', error),\n * });\n *\n * const handlePickFiles = async () => {\n * const files = await fileSystemProvider.pickImage({ allowMultiple: true });\n * multiUpload.addFiles(files);\n * await multiUpload.startUploads();\n * };\n *\n * return (\n * <View>\n * <Button title=\"Pick Files\" onPress={handlePickFiles} />\n * <Text>Progress: {multiUpload.state.totalProgress}%</Text>\n * <Text>Active: {multiUpload.state.activeCount}</Text>\n * <Text>Completed: {multiUpload.state.completedCount}/{multiUpload.state.items.length}</Text>\n * </View>\n * );\n * }\n * ```\n */\nexport function useMultiUpload(options: UseMultiUploadOptions = {}) {\n const { client } = useUploadistaContext();\n const [state, setState] = useState<MultiUploadState>(initialState);\n const abortControllersRef = useRef<Map<string, { abort: () => void }>>(\n new Map(),\n );\n const nextIdRef = useRef(0);\n // Use ref to track items synchronously\n const itemsRef = useRef<UploadItemState[]>([]);\n\n const generateId = useCallback(() => {\n return `upload-${Date.now()}-${nextIdRef.current++}`;\n }, []);\n\n const updateAggregateStats = useCallback((items: UploadItemState[]) => {\n const totalBytes = items.reduce((sum, item) => sum + item.totalBytes, 0);\n const totalUploaded = items.reduce(\n (sum, item) => sum + item.bytesUploaded,\n 0,\n );\n const totalProgress =\n totalBytes > 0 ? Math.round((totalUploaded / totalBytes) * 100) : 0;\n const activeCount = items.filter(\n (item) => item.status === \"uploading\",\n ).length;\n const completedCount = items.filter(\n (item) => item.status === \"success\",\n ).length;\n const failedCount = items.filter((item) => item.status === \"error\").length;\n\n // Update ref synchronously\n itemsRef.current = items;\n\n setState((prev) => ({\n ...prev,\n items,\n totalProgress,\n totalUploaded,\n totalBytes,\n activeCount,\n completedCount,\n failedCount,\n }));\n }, []);\n\n const addFiles = useCallback(\n (files: FilePickResult[]) => {\n // Filter out cancelled and error results, only keep successful picks\n const successfulFiles = files.filter(\n (file): file is Extract<FilePickResult, { status: \"success\" }> =>\n file.status === \"success\",\n );\n\n const newItems: UploadItemState[] = successfulFiles.map((file) => ({\n id: generateId(),\n file,\n status: \"idle\" as const,\n progress: 0,\n bytesUploaded: 0,\n totalBytes: file.data.size,\n error: null,\n result: null,\n }));\n\n // Update ref synchronously\n const updatedItems = [...itemsRef.current, ...newItems];\n itemsRef.current = updatedItems;\n\n setState((prev) => {\n const totalBytes = updatedItems.reduce(\n (sum, item) => sum + item.totalBytes,\n 0,\n );\n return {\n ...prev,\n items: updatedItems,\n totalBytes,\n };\n });\n\n return newItems.map((item) => item.id);\n },\n [generateId],\n );\n\n const uploadSingleItem = useCallback(\n async (item: UploadItemState) => {\n try {\n console.log(\"Uploading item:\", item.file.data.name);\n // Update status to uploading\n const updatedItems = itemsRef.current.map((i) =>\n i.id === item.id ? { ...i, status: \"uploading\" as const } : i,\n );\n updateAggregateStats(updatedItems);\n\n // Convert file URI to Blob using fetch (React Native compatible)\n // React Native's Blob doesn't support ArrayBuffer/Uint8Array constructor\n const response = await fetch(item.file.data.uri);\n const blob = await response.blob();\n\n // Override blob type if we have mimeType from picker\n const uploadInput = item.file.data.mimeType\n ? new Blob([blob], { type: item.file.data.mimeType })\n : blob;\n\n // Start upload using the client\n console.log(\"Uploading input:\", uploadInput);\n const uploadPromise = client.upload(uploadInput, {\n metadata: options.metadata,\n\n onProgress: (\n _uploadId: string,\n bytesUploaded: number,\n totalBytes: number | null,\n ) => {\n const progress = totalBytes\n ? Math.round((bytesUploaded / totalBytes) * 100)\n : 0;\n\n const updatedItems = itemsRef.current.map((i) =>\n i.id === item.id\n ? {\n ...i,\n progress,\n bytesUploaded,\n totalBytes: totalBytes || i.totalBytes,\n }\n : i,\n );\n updateAggregateStats(updatedItems);\n },\n\n onSuccess: (result: UploadFile) => {\n const updatedItems = itemsRef.current.map((i) =>\n i.id === item.id\n ? {\n ...i,\n status: \"success\" as const,\n progress: 100,\n result,\n bytesUploaded: result.size || i.totalBytes,\n }\n : i,\n );\n updateAggregateStats(updatedItems);\n\n options.onSuccess?.(result);\n abortControllersRef.current.delete(item.id);\n },\n\n onError: (error: Error) => {\n const updatedItems = itemsRef.current.map((i) =>\n i.id === item.id ? { ...i, status: \"error\" as const, error } : i,\n );\n updateAggregateStats(updatedItems);\n\n options.onError?.(error);\n abortControllersRef.current.delete(item.id);\n },\n });\n\n // Store abort controller\n const controller = await uploadPromise;\n abortControllersRef.current.set(item.id, controller);\n } catch (error) {\n console.error(\"Error uploading item:\", error);\n const updatedItems = itemsRef.current.map((i) =>\n i.id === item.id\n ? {\n ...i,\n status: \"error\" as const,\n error: error as Error,\n }\n : i,\n );\n updateAggregateStats(updatedItems);\n\n options.onError?.(error as Error);\n abortControllersRef.current.delete(item.id);\n }\n },\n [client, options, updateAggregateStats],\n );\n\n const startUploads = useCallback(\n async (itemIds?: string[]) => {\n const maxConcurrent = options.maxConcurrent || 3;\n\n // Get items from ref (synchronous access to latest items)\n const itemsToUpload = itemIds\n ? itemsRef.current.filter(\n (item) => itemIds.includes(item.id) && item.status === \"idle\",\n )\n : itemsRef.current.filter((item) => item.status === \"idle\");\n\n console.log(\"Items to upload:\", itemsToUpload.length, itemsToUpload);\n\n // Process items in batches\n for (let i = 0; i < itemsToUpload.length; i += maxConcurrent) {\n const batch = itemsToUpload.slice(i, i + maxConcurrent);\n await Promise.all(batch.map((item) => uploadSingleItem(item)));\n }\n },\n [options.maxConcurrent, uploadSingleItem],\n );\n\n const removeItem = useCallback(\n (id: string) => {\n const controller = abortControllersRef.current.get(id);\n if (controller) {\n controller.abort();\n abortControllersRef.current.delete(id);\n }\n\n const updatedItems = itemsRef.current.filter((item) => item.id !== id);\n updateAggregateStats(updatedItems);\n },\n [updateAggregateStats],\n );\n\n const abortItem = useCallback(\n (id: string) => {\n const controller = abortControllersRef.current.get(id);\n if (controller) {\n controller.abort();\n abortControllersRef.current.delete(id);\n }\n\n const updatedItems = itemsRef.current.map((item) =>\n item.id === id ? { ...item, status: \"aborted\" as const } : item,\n );\n updateAggregateStats(updatedItems);\n },\n [updateAggregateStats],\n );\n\n const clear = useCallback(() => {\n // Abort all active uploads\n abortControllersRef.current.forEach((controller) => {\n controller.abort();\n });\n abortControllersRef.current.clear();\n\n // Clear ref\n itemsRef.current = [];\n\n setState(initialState);\n }, []);\n\n const retryItem = useCallback(\n async (id: string) => {\n const item = itemsRef.current.find((i) => i.id === id);\n if (item && (item.status === \"error\" || item.status === \"aborted\")) {\n // Reset item status to idle\n const updatedItems = itemsRef.current.map((i) =>\n i.id === id\n ? {\n ...i,\n status: \"idle\" as const,\n progress: 0,\n bytesUploaded: 0,\n error: null,\n }\n : i,\n );\n updateAggregateStats(updatedItems);\n\n // Upload it (get the reset item from the updated items)\n const resetItem = itemsRef.current.find((i) => i.id === id);\n if (resetItem) {\n await uploadSingleItem(resetItem);\n }\n }\n },\n [uploadSingleItem, updateAggregateStats],\n );\n\n return {\n state,\n addFiles,\n startUploads,\n removeItem,\n abortItem,\n retryItem,\n clear,\n };\n}\n","import { useCallback } from \"react\";\nimport type { FilePickResult, UseGalleryUploadOptions } from \"../types\";\nimport { useMultiUpload } from \"./use-multi-upload\";\nimport { useUploadistaContext } from \"./use-uploadista-context\";\n\n/**\n * Hook for selecting and uploading photos/videos from gallery\n * Handles batch selection and concurrent uploads\n * @param options - Gallery upload configuration\n * @returns Upload state and gallery selection/upload function\n */\nexport function useGalleryUpload(options?: UseGalleryUploadOptions) {\n const { fileSystemProvider } = useUploadistaContext();\n const uploadHook = useMultiUpload({\n maxConcurrent: 3,\n metadata: options?.metadata,\n onSuccess: options?.onSuccess,\n onError: options?.onError,\n });\n\n // Select and upload media from gallery\n const selectAndUpload = useCallback(async () => {\n let result: FilePickResult;\n\n // Select appropriate media type\n if (options?.mediaType === \"video\") {\n result = await fileSystemProvider.pickVideo({\n allowMultiple: options?.allowMultiple ?? true,\n });\n } else if (options?.mediaType === \"photo\") {\n result = await fileSystemProvider.pickImage({\n allowMultiple: options?.allowMultiple ?? true,\n });\n } else {\n // For 'mixed' or default, use pickImage first (can be extended to support both)\n result = await fileSystemProvider.pickImage({\n allowMultiple: options?.allowMultiple ?? true,\n });\n }\n\n // Handle cancelled picker\n if (result.status === \"cancelled\") {\n return [];\n }\n\n // Handle picker error\n if (result.status === \"error\") {\n console.error(\"Gallery selection error:\", result.error);\n options?.onError?.(result.error);\n return [];\n }\n\n // Success - add file and start upload\n const itemIds = uploadHook.addFiles([result]);\n console.log(\"starting uploads\", itemIds);\n await uploadHook.startUploads(itemIds);\n console.log(\"uploads started\", itemIds);\n\n return itemIds;\n }, [\n fileSystemProvider,\n options?.allowMultiple,\n options?.mediaType,\n options?.onError,\n uploadHook,\n ]);\n\n return {\n ...uploadHook,\n selectAndUpload,\n };\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport type { UploadMetrics } from \"../types\";\n\n/**\n * Hook for tracking upload performance metrics\n * @returns Metrics object and methods to track uploads\n */\nexport function useUploadMetrics() {\n const startTimeRef = useRef<number | null>(null);\n const startBytesRef = useRef<number>(0);\n const peakSpeedRef = useRef<number>(0);\n\n const [metrics, setMetrics] = useState<UploadMetrics>({\n totalBytes: 0,\n durationMs: 0,\n avgSpeed: 0,\n peakSpeed: 0,\n retries: 0,\n });\n\n // Start tracking\n const start = useCallback(() => {\n startTimeRef.current = Date.now();\n startBytesRef.current = 0;\n peakSpeedRef.current = 0;\n }, []);\n\n // Update metrics based on current progress\n const update = useCallback(\n (uploadedBytes: number, _totalBytes: number, currentRetries = 0) => {\n if (!startTimeRef.current) {\n return;\n }\n\n const now = Date.now();\n const durationMs = now - startTimeRef.current;\n const speed = durationMs > 0 ? (uploadedBytes / durationMs) * 1000 : 0;\n\n if (speed > peakSpeedRef.current) {\n peakSpeedRef.current = speed;\n }\n\n setMetrics({\n totalBytes: uploadedBytes,\n durationMs,\n avgSpeed: durationMs > 0 ? (uploadedBytes / durationMs) * 1000 : 0,\n peakSpeed: peakSpeedRef.current,\n retries: currentRetries,\n });\n },\n [],\n );\n\n // End tracking and return final metrics\n const end = useCallback(() => {\n const finalMetrics = metrics;\n startTimeRef.current = null;\n return finalMetrics;\n }, [metrics]);\n\n // Reset metrics\n const reset = useCallback(() => {\n startTimeRef.current = null;\n startBytesRef.current = 0;\n peakSpeedRef.current = 0;\n setMetrics({\n totalBytes: 0,\n durationMs: 0,\n avgSpeed: 0,\n peakSpeed: 0,\n retries: 0,\n });\n }, []);\n\n return {\n metrics,\n start,\n update,\n end,\n reset,\n };\n}\n","/**\n * File utility functions for React Native uploads\n */\n\n/**\n * Format file size to human readable string\n * @param bytes - Size in bytes\n * @returns Formatted size string (e.g., \"1.5 MB\")\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes === 0) return \"0 Bytes\";\n\n const k = 1024;\n const sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n\n return `${Math.round((bytes / k ** i) * 100) / 100} ${sizes[i]}`;\n}\n\n/**\n * Get MIME type from file name\n * @param fileName - File name with extension\n * @returns MIME type or 'application/octet-stream' as fallback\n */\nexport function getMimeTypeFromFileName(fileName: string): string {\n const mimeTypes: Record<string, string> = {\n // Images\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".png\": \"image/png\",\n \".gif\": \"image/gif\",\n \".bmp\": \"image/bmp\",\n \".webp\": \"image/webp\",\n \".svg\": \"image/svg+xml\",\n\n // Videos\n \".mp4\": \"video/mp4\",\n \".avi\": \"video/x-msvideo\",\n \".mov\": \"video/quicktime\",\n \".wmv\": \"video/x-ms-wmv\",\n \".flv\": \"video/x-flv\",\n \".mkv\": \"video/x-matroska\",\n \".webm\": \"video/webm\",\n\n // Audio\n \".mp3\": \"audio/mpeg\",\n \".wav\": \"audio/wav\",\n \".aac\": \"audio/aac\",\n \".flac\": \"audio/flac\",\n \".m4a\": \"audio/mp4\",\n\n // Documents\n \".pdf\": \"application/pdf\",\n \".doc\": \"application/msword\",\n \".docx\":\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n \".xls\": \"application/vnd.ms-excel\",\n \".xlsx\":\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n \".ppt\": \"application/vnd.ms-powerpoint\",\n \".pptx\":\n \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n \".txt\": \"text/plain\",\n \".csv\": \"text/csv\",\n \".json\": \"application/json\",\n \".xml\": \"application/xml\",\n \".zip\": \"application/zip\",\n };\n\n const ext = fileName.toLowerCase().slice(fileName.lastIndexOf(\".\"));\n return mimeTypes[ext] || \"application/octet-stream\";\n}\n\n/**\n * Check if file type is allowed\n * @param fileName - File name to check\n * @param allowedTypes - Array of allowed MIME types (e.g., ['image/jpeg', 'image/png'])\n * @returns True if file type is allowed\n */\nexport function isFileTypeAllowed(\n fileName: string,\n allowedTypes: string[],\n): boolean {\n if (!allowedTypes || allowedTypes.length === 0) {\n return true;\n }\n\n const mimeType = getMimeTypeFromFileName(fileName);\n return allowedTypes.some((allowed) => {\n if (allowed.endsWith(\"/*\")) {\n // Handle wildcard patterns like 'image/*'\n const [type] = allowed.split(\"/\");\n return mimeType.startsWith(`${type}/`);\n }\n return allowed === mimeType;\n });\n}\n\n/**\n * Check if file size is within limits\n * @param fileSize - File size in bytes\n * @param maxSize - Maximum allowed size in bytes (optional)\n * @param minSize - Minimum allowed size in bytes (optional)\n * @returns True if file size is within limits\n */\nexport function isFileSizeValid(\n fileSize: number,\n maxSize?: number,\n minSize?: number,\n): boolean {\n if (maxSize !== undefined && fileSize > maxSize) {\n return false;\n }\n\n if (minSize !== undefined && fileSize < minSize) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Get file extension\n * @param fileName - File name\n * @returns File extension without dot (e.g., 'pdf' for 'document.pdf')\n */\nexport function getFileExtension(fileName: string): string {\n const lastDot = fileName.lastIndexOf(\".\");\n if (lastDot === -1) return \"\";\n return fileName.slice(lastDot + 1).toLowerCase();\n}\n\n/**\n * Get file name without extension\n * @param fileName - File name\n * @returns File name without extension\n */\nexport function getFileNameWithoutExtension(fileName: string): string {\n const lastDot = fileName.lastIndexOf(\".\");\n if (lastDot === -1) return fileName;\n return fileName.slice(0, lastDot);\n}\n\n/**\n * Check if file is an image\n * @param fileName - File name\n * @returns True if file is an image\n */\nexport function isImageFile(fileName: string): boolean {\n const imageExtensions = [\n \".jpg\",\n \".jpeg\",\n \".png\",\n \".gif\",\n \".bmp\",\n \".webp\",\n \".svg\",\n ];\n const ext = fileName.toLowerCase().slice(fileName.lastIndexOf(\".\"));\n return imageExtensions.includes(ext);\n}\n\n/**\n * Check if file is a video\n * @param fileName - File name\n * @returns True if file is a video\n */\nexport function isVideoFile(fileName: string): boolean {\n const videoExtensions = [\n \".mp4\",\n \".avi\",\n \".mov\",\n \".wmv\",\n \".flv\",\n \".mkv\",\n \".webm\",\n ];\n const ext = fileName.toLowerCase().slice(fileName.lastIndexOf(\".\"));\n return videoExtensions.includes(ext);\n}\n\n/**\n * Check if file is a document\n * @param fileName - File name\n * @returns True if file is a document\n */\nexport function isDocumentFile(fileName: string): boolean {\n const docExtensions = [\n \".pdf\",\n \".doc\",\n \".docx\",\n \".xls\",\n \".xlsx\",\n \".ppt\",\n \".pptx\",\n \".txt\",\n \".csv\",\n ];\n const ext = fileName.toLowerCase().slice(fileName.lastIndexOf(\".\"));\n return docExtensions.includes(ext);\n}\n","/**\n * Permission utility functions for React Native uploads\n * Handles camera, gallery, and file access permissions\n */\n\n/**\n * Permission types\n */\nexport enum PermissionType {\n CAMERA = \"CAMERA\",\n PHOTO_LIBRARY = \"PHOTO_LIBRARY\",\n WRITE_STORAGE = \"WRITE_STORAGE\",\n READ_STORAGE = \"READ_STORAGE\",\n}\n\n/**\n * Permission status\n */\nexport enum PermissionStatus {\n GRANTED = \"granted\",\n DENIED = \"denied\",\n NOT_DETERMINED = \"not_determined\",\n RESTRICTED = \"restricted\",\n}\n\n/**\n * Request camera permission\n * This is primarily used to check if we should attempt camera operations\n * Actual permission requests are handled by the file system providers\n *\n * @returns Promise resolving to true if permission is granted or already granted\n */\nexport async function requestCameraPermission(): Promise<boolean> {\n try {\n // Permission requests are handled by the file system provider implementations\n // This function serves as a placeholder for app-level permission handling\n console.log(\n \"Camera permission requested (handled by file system provider)\",\n );\n return true;\n } catch (error) {\n console.error(\"Failed to request camera permission:\", error);\n return false;\n }\n}\n\n/**\n * Request photo library permission\n * @returns Promise resolving to true if permission is granted\n */\nexport async function requestPhotoLibraryPermission(): Promise<boolean> {\n try {\n console.log(\n \"Photo library permission requested (handled by file system provider)\",\n );\n return true;\n } catch (error) {\n console.error(\"Failed to request photo library permission:\", error);\n return false;\n }\n}\n\n/**\n * Request storage read permission\n * @returns Promise resolving to true if permission is granted\n */\nexport async function requestStorageReadPermission(): Promise<boolean> {\n try {\n console.log(\n \"Storage read permission requested (handled by file system provider)\",\n );\n return true;\n } catch (error) {\n console.error(\"Failed to request storage read permission:\", error);\n return false;\n }\n}\n\n/**\n * Request storage write permission\n * @returns Promise resolving to true if permission is granted\n */\nexport async function requestStorageWritePermission(): Promise<boolean> {\n try {\n console.log(\n \"Storage write permission requested (handled by file system provider)\",\n );\n return true;\n } catch (error) {\n console.error(\"Failed to request storage write permission:\", error);\n return false;\n }\n}\n\n/**\n * Request multiple permissions at once\n * @param permissions - Array of permission types to request\n * @returns Promise resolving to true if all permissions are granted\n */\nexport async function requestPermissions(\n permissions: PermissionType[],\n): Promise<boolean> {\n try {\n const results = await Promise.all(\n permissions.map(async (permission) => {\n switch (permission) {\n case PermissionType.CAMERA:\n return requestCameraPermission();\n case PermissionType.PHOTO_LIBRARY:\n return requestPhotoLibraryPermission();\n case PermissionType.READ_STORAGE:\n return requestStorageReadPermission();\n case PermissionType.WRITE_STORAGE:\n return requestStorageWritePermission();\n default:\n return false;\n }\n }),\n );\n\n return results.every((result) => result);\n } catch (error) {\n console.error(\"Failed to request permissions:\", error);\n return false;\n }\n}\n\n/**\n * Check if all required permissions are granted\n * @param permissions - Array of permission types to check\n * @returns Promise resolving to true if all permissions are granted\n */\nexport async function hasPermissions(\n _permissions: PermissionType[],\n): Promise<boolean> {\n try {\n // In React Native, permission checking is typically handled by the platform\n // This is a placeholder that assumes permissions will be handled by the file system provider\n return true;\n } catch (error) {\n console.error(\"Failed to check permissions:\", error);\n return false;\n }\n}\n\n/**\n * Get permission status\n * @param permission - Permission type to check\n * @returns Promise resolving to permission status\n */\nexport async function getPermissionStatus(\n _permission: PermissionType,\n): Promise<PermissionStatus> {\n try {\n // This is a placeholder implementation\n // Real implementation would use platform-specific APIs\n return PermissionStatus.GRANTED;\n } catch (error) {\n console.error(\"Failed to get permission status:\", error);\n return PermissionStatus.DENIED;\n }\n}\n\n/**\n * Open app settings to request permissions\n * Guides user to app settings where they can manually enable permissions\n */\nexport function openAppSettings(): void {\n try {\n // This would typically use react-native-app-settings or similar\n console.log(\n \"Opening app settings (requires react-native-app-settings or platform implementation)\",\n );\n } catch (error) {\n console.error(\"Failed to open app settings:\", error);\n }\n}\n","/**\n * URI utility functions for React Native file handling\n */\n\n/**\n * Extract file name from URI\n * @param uri - File URI\n * @returns File name extracted from URI\n */\nexport function getFileNameFromUri(uri: string): string {\n try {\n // Handle different URI formats\n if (uri.startsWith(\"file://\")) {\n // File URI format\n const path = uri.replace(\"file://\", \"\");\n return path.split(\"/\").pop() || \"file\";\n }\n\n if (uri.startsWith(\"content://\")) {\n // Content URI format (Android)\n const parts = uri.split(\"/\");\n return parts[parts.length - 1] || \"file\";\n }\n\n // Assume it's a path or other format\n const parts = uri.split(\"/\");\n return parts[parts.length - 1] || \"file\";\n } catch {\n return \"file\";\n }\n}\n\n/**\n * Convert file path to file URI\n * @param filePath - File path\n * @returns File URI\n */\nexport function pathToUri(filePath: string): string {\n if (filePath.startsWith(\"file://\")) {\n return filePath;\n }\n\n if (filePath.startsWith(\"content://\")) {\n return filePath;\n }\n\n // Convert to file URI\n return `file://${filePath}`;\n}\n\n/**\n * Convert file URI to file path\n * @param uri - File URI\n * @returns File path\n */\nexport function uriToPath(uri: string): string {\n if (uri.startsWith(\"file://\")) {\n return uri.replace(\"file://\", \"\");\n }\n\n if (uri.startsWith(\"content://\")) {\n // Content URIs cannot be converted to paths directly\n return uri;\n }\n\n return uri;\n}\n\n/**\n * Get directory from URI\n * @param uri - File URI\n * @returns Directory path\n */\nexport function getDirectoryFromUri(uri: string): string {\n try {\n const path = uriToPath(uri);\n const parts = path.split(\"/\");\n parts.pop(); // Remove file name\n return parts.join(\"/\");\n } catch {\n return \"\";\n }\n}\n\n/**\n * Check if URI is a content URI (Android specific)\n * @param uri - URI to check\n * @returns True if URI is a content URI\n */\nexport function isContentUri(uri: string): boolean {\n return uri.startsWith(\"content://\");\n}\n\n/**\n * Check if URI is a file URI\n * @param uri - URI to check\n * @returns True if URI is a file URI\n */\nexport function isFileUri(uri: string): boolean {\n return uri.startsWith(\"file://\");\n}\n\n/**\n * Normalize URI for cross-platform compatibility\n * @param uri - URI to normalize\n * @returns Normalized URI\n */\nexport function normalizeUri(uri: string): string {\n // Remove duplicate slashes (but keep protocol slashes)\n return uri.replace(/([^:]\\/)\\/+/g, \"$1\");\n}\n\n/**\n * Get MIME type hint from URI\n * @param uri - File URI\n * @returns MIME type hint based on file extension\n */\nexport function getMimeTypeFromUri(uri: string): string {\n const fileName = getFileNameFromUri(uri);\n\n const mimeTypes: Record<string, string> = {\n // Images\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".png\": \"image/png\",\n \".gif\": \"image/gif\",\n \".bmp\": \"image/bmp\",\n \".webp\": \"image/webp\",\n\n // Videos\n \".mp4\": \"video/mp4\",\n \".mov\": \"video/quicktime\",\n \".avi\": \"video/x-msvideo\",\n\n // Audio\n \".mp3\": \"audio/mpeg\",\n \".wav\": \"audio/wav\",\n \".aac\": \"audio/aac\",\n\n // Documents\n \".pdf\": \"application/pdf\",\n \".txt\": \"text/plain\",\n \".json\": \"application/json\",\n };\n\n const ext = fileName.toLowerCase().slice(fileName.lastIndexOf(\".\"));\n return mimeTypes[ext] || \"application/octet-stream\";\n}\n","import { ActivityIndicator, StyleSheet, Text, View } from \"react-native\";\nimport type { UploadState } from \"../hooks/use-upload\";\nimport { formatFileSize } from \"../utils\";\n\nexport interface UploadProgressProps {\n /** Upload state information */\n state: UploadState;\n /** Optional custom label */\n label?: string;\n}\n\n/**\n * Component to display upload progress with percentage, size, and speed\n */\nexport function UploadProgress({ state, label }: UploadProgressProps) {\n const getStatusColor = () => {\n switch (state.status) {\n case \"uploading\":\n return \"#007AFF\";\n case \"success\":\n return \"#34C759\";\n case \"error\":\n case \"aborted\":\n return \"#FF3B30\";\n default:\n return \"#999999\";\n }\n };\n\n const renderContent = () => {\n switch (state.status) {\n case \"idle\":\n return (\n <View style={styles.container}>\n <Text style={styles.label}>{label || \"Ready to upload\"}</Text>\n </View>\n );\n\n case \"uploading\":\n return (\n <View style={styles.container}>\n <View style={styles.headerRow}>\n <Text style={styles.label}>{label || \"Uploading\"}</Text>\n <Text style={styles.percentage}>{state.progress}%</Text>\n </View>\n\n {/* Progress bar */}\n <View style={styles.progressBarContainer}>\n <View\n style={[\n styles.progressBar,\n {\n width: `${state.progress}%`,\n backgroundColor: getStatusColor(),\n },\n ]}\n />\n </View>\n\n {/* Details row */}\n <View style={styles.detailsRow}>\n <Text style={styles.detail}>\n {formatFileSize(state.bytesUploaded)} /{\" \"}\n {formatFileSize(state.totalBytes || 0)}\n </Text>\n </View>\n </View>\n );\n\n case \"success\":\n return (\n <View style={styles.container}>\n <View style={styles.headerRow}>\n <Text style={[styles.label, { color: getStatusColor() }]}>\n {label || \"Upload complete\"}\n </Text>\n <Text style={[styles.percentage, { color: getStatusColor() }]}>\n ✓\n </Text>\n </View>\n <Text style={[styles.detail, { color: getStatusColor() }]}>\n {formatFileSize(state.totalBytes || 0)}\n </Text>\n </View>\n );\n\n case \"error\":\n return (\n <View style={styles.container}>\n <View style={styles.headerRow}>\n <Text style={[styles.label, { color: getStatusColor() }]}>\n {label || \"Upload failed\"}\n </Text>\n <Text style={[styles.percentage, { color: getStatusColor() }]}>\n ✕\n </Text>\n </View>\n {state.error && (\n <Text style={[styles.detail, { color: getStatusColor() }]}>\n {state.error.message}\n </Text>\n )}\n </View>\n );\n\n case \"aborted\":\n return (\n <View style={styles.container}>\n <Text style={[styles.label, { color: getStatusColor() }]}>\n {label || \"Upload cancelled\"}\n </Text>\n </View>\n );\n\n default:\n return null;\n }\n };\n\n return (\n <View\n style={[\n styles.wrapper,\n {\n borderLeftColor: getStatusColor(),\n },\n ]}\n >\n {state.status === \"uploading\" && (\n <ActivityIndicator\n size=\"small\"\n color={getStatusColor()}\n style={styles.spinner}\n />\n )}\n {renderContent()}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n wrapper: {\n flexDirection: \"row\",\n alignItems: \"flex-start\",\n paddingVertical: 8,\n paddingHorizontal: 12,\n borderLeftWidth: 4,\n backgroundColor: \"#f5f5f5\",\n borderRadius: 4,\n gap: 8,\n },\n spinner: {\n marginTop: 4,\n },\n container: {\n flex: 1,\n gap: 4,\n },\n headerRow: {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n },\n label: {\n fontSize: 14,\n fontWeight: \"600\",\n color: \"#333333\",\n flex: 1,\n },\n percentage: {\n fontSize: 14,\n fontWeight: \"600\",\n color: \"#007AFF\",\n minWidth: 36,\n textAlign: \"right\",\n },\n progressBarContainer: {\n height: 4,\n backgroundColor: \"#e0e0e0\",\n borderRadius: 2,\n overflow: \"hidden\",\n },\n progressBar: {\n height: \"100%\",\n borderRadius: 2,\n },\n detailsRow: {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n },\n detail: {\n fontSize: 12,\n color: \"#666666\",\n },\n});\n","import { type ReactNode, useEffect } from \"react\";\nimport {\n ActivityIndicator,\n Pressable,\n StyleSheet,\n Text,\n View,\n} from \"react-native\";\nimport { useCameraUpload } from \"../hooks\";\nimport type { UseCameraUploadOptions } from \"../types\";\nimport { UploadProgress } from \"./UploadProgress\";\n\nexport interface CameraUploadButtonProps {\n /** Options for camera upload */\n options?: UseCameraUploadOptions;\n /** Button label text */\n label?: string;\n /** Custom button content */\n children?: ReactNode;\n /** Callback when upload completes successfully */\n onSuccess?: (result: unknown) => void;\n /** Callback when upload fails */\n onError?: (error: Error) => void;\n /** Callback when upload is cancelled */\n onCancel?: () => void;\n /** Whether to show progress inline */\n showProgress?: boolean;\n}\n\n/**\n * Button component for camera capture and upload\n * Triggers camera on press and handles upload with progress display\n */\nexport function CameraUploadButton({\n options,\n label = \"Take Photo\",\n children,\n onSuccess,\n onError,\n onCancel,\n showProgress = true,\n}: CameraUploadButtonProps) {\n const { state, captureAndUpload } = useCameraUpload(options);\n\n const handlePress = async () => {\n try {\n await captureAndUpload();\n } catch (error) {\n if (error instanceof Error) {\n if (\n error.message.includes(\"cancelled\") ||\n error.message.includes(\"aborted\")\n ) {\n onCancel?.();\n } else {\n onError?.(error);\n }\n }\n }\n };\n\n const isLoading = state.status === \"uploading\";\n const isDisabled = isLoading || state.status === \"aborted\";\n\n useEffect(() => {\n if (state.status === \"success\" && state.result) {\n onSuccess?.(state.result);\n }\n }, [state.status, state.result, onSuccess]);\n\n useEffect(() => {\n if (state.status === \"error\" && state.error) {\n onError?.(state.error);\n }\n }, [state.status, state.error, onError]);\n\n return (\n <View style={styles.container}>\n <Pressable\n style={[styles.button, isDisabled && styles.buttonDisabled]}\n onPress={handlePress}\n disabled={isDisabled}\n >\n {isLoading && (\n <ActivityIndicator\n size=\"small\"\n color=\"#FFFFFF\"\n style={styles.spinner}\n />\n )}\n <Text style={styles.buttonText}>{children || label}</Text>\n </Pressable>\n {showProgress && state.status !== \"idle\" && (\n <View style={styles.progressContainer}>\n <UploadProgress state={state} label=\"Camera upload\" />\n </View>\n )}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n gap: 8,\n },\n button: {\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"center\",\n paddingVertical: 12,\n paddingHorizontal: 16,\n backgroundColor: \"#007AFF\",\n borderRadius: 8,\n gap: 8,\n },\n buttonDisabled: {\n opacity: 0.6,\n },\n buttonText: {\n fontSize: 16,\n fontWeight: \"600\",\n color: \"#FFFFFF\",\n },\n spinner: {\n marginRight: 4,\n },\n progressContainer: {\n marginTop: 4,\n },\n});\n","import { type ReactNode, useEffect } from \"react\";\nimport {\n ActivityIndicator,\n Pressable,\n StyleSheet,\n Text,\n View,\n} from \"react-native\";\nimport { useFileUpload } from \"../hooks\";\nimport type { UseFileUploadOptions } from \"../types\";\nimport { UploadProgress } from \"./UploadProgress\";\n\nexport interface FileUploadButtonProps {\n /** Options for file upload */\n options?: UseFileUploadOptions;\n /** Button label text */\n label?: string;\n /** Custom button content */\n children?: ReactNode;\n /** Callback when upload completes successfully */\n onSuccess?: (result: unknown) => void;\n /** Callback when upload fails */\n onError?: (error: Error) => void;\n /** Callback when upload is cancelled */\n onCancel?: () => void;\n /** Whether to show progress inline */\n showProgress?: boolean;\n}\n\n/**\n * Button component for document/file selection and upload\n * Generic file picker with progress display\n */\nexport function FileUploadButton({\n options,\n label = \"Choose File\",\n children,\n onSuccess,\n onError,\n onCancel,\n showProgress = true,\n}: FileUploadButtonProps) {\n const { state, pickAndUpload } = useFileUpload(options);\n\n const handlePress = async () => {\n try {\n await pickAndUpload();\n } catch (error) {\n if (error instanceof Error) {\n if (\n error.message.includes(\"cancelled\") ||\n error.message.includes(\"aborted\")\n ) {\n onCancel?.();\n } else {\n onError?.(error);\n }\n }\n }\n };\n\n const isLoading = state.status === \"uploading\";\n const isDisabled = isLoading || state.status === \"aborted\";\n\n useEffect(() => {\n if (state.status === \"success\" && state.result) {\n onSuccess?.(state.result);\n }\n }, [state.status, state.result, onSuccess]);\n\n useEffect(() => {\n if (state.status === \"error\" && state.error) {\n onError?.(state.error);\n }\n }, [state.status, state.error, onError]);\n\n return (\n <View style={styles.container}>\n <Pressable\n style={[styles.button, isDisabled && styles.buttonDisabled]}\n onPress={handlePress}\n disabled={isDisabled}\n >\n {isLoading && (\n <ActivityIndicator\n size=\"small\"\n color=\"#FFFFFF\"\n style={styles.spinner}\n />\n )}\n <Text style={styles.buttonText}>{children || label}</Text>\n </Pressable>\n {showProgress && state.status !== \"idle\" && (\n <View style={styles.progressContainer}>\n <UploadProgress state={state} label=\"File upload\" />\n </View>\n )}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n gap: 8,\n },\n button: {\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"center\",\n paddingVertical: 12,\n paddingHorizontal: 16,\n backgroundColor: \"#FF9500\",\n borderRadius: 8,\n gap: 8,\n },\n buttonDisabled: {\n opacity: 0.6,\n },\n buttonText: {\n fontSize: 16,\n fontWeight: \"600\",\n color: \"#FFFFFF\",\n },\n spinner: {\n marginRight: 4,\n },\n progressContainer: {\n marginTop: 4,\n },\n});\n","import React, { type ReactNode } from \"react\";\nimport {\n ActivityIndicator,\n FlatList,\n Pressable,\n StyleSheet,\n Text,\n View,\n} from \"react-native\";\nimport { useGalleryUpload } from \"../hooks\";\nimport type { UseGalleryUploadOptions } from \"../types\";\nimport { UploadProgress } from \"./UploadProgress\";\n\nexport interface GalleryUploadButtonProps {\n /** Options for gallery upload */\n options?: UseGalleryUploadOptions;\n /** Button label text */\n label?: string;\n /** Custom button content */\n children?: ReactNode;\n /** Callback when all uploads complete successfully */\n onSuccess?: (results: unknown[]) => void;\n /** Callback when any upload fails */\n onError?: (error: Error) => void;\n /** Callback when upload is cancelled */\n onCancel?: () => void;\n /** Whether to show individual progress for each file */\n showProgress?: boolean;\n}\n\n/**\n * Button component for gallery selection and batch upload\n * Triggers gallery picker on press and handles concurrent uploads\n */\nexport function GalleryUploadButton({\n options,\n label = \"Select from Gallery\",\n children,\n onSuccess,\n onError,\n onCancel,\n showProgress = true,\n}: GalleryUploadButtonProps) {\n const { state, selectAndUpload } = useGalleryUpload(options);\n\n const handlePress = async () => {\n try {\n await selectAndUpload();\n } catch (error) {\n if (error instanceof Error) {\n if (\n error.message.includes(\"cancelled\") ||\n error.message.includes(\"aborted\")\n ) {\n onCancel?.();\n } else {\n onError?.(error);\n }\n }\n }\n };\n\n const isLoading = state.items.some((item) => item.status === \"uploading\");\n const hasItems = state.items.length > 0;\n const allComplete =\n hasItems &&\n state.items.every(\n (item) => item.status !== \"uploading\" && item.status !== \"idle\",\n );\n\n React.useEffect(() => {\n if (allComplete) {\n const results = state.items\n .filter((item) => item.status === \"success\")\n .map((item) => item.result);\n if (results.length > 0) {\n onSuccess?.(results);\n }\n }\n }, [allComplete, state.items, onSuccess]);\n\n React.useEffect(() => {\n const errors = state.items.filter((item) => item.status === \"error\");\n const firstError = errors[0]?.error;\n if (firstError) {\n onError?.(firstError);\n }\n }, [state.items, onError]);\n\n const renderItem = ({ item }: { item: (typeof state.items)[0] }) => (\n <View key={item.id} style={styles.itemContainer}>\n <UploadProgress\n state={{\n status: item.status,\n progress: item.progress,\n bytesUploaded: item.bytesUploaded,\n totalBytes: item.totalBytes,\n error: item.error,\n result: item.result,\n }}\n label={item.file.data.name}\n />\n </View>\n );\n\n return (\n <View style={styles.container}>\n <Pressable\n style={[styles.button, isLoading && styles.buttonDisabled]}\n onPress={handlePress}\n disabled={isLoading}\n >\n {isLoading && (\n <ActivityIndicator\n size=\"small\"\n color=\"#FFFFFF\"\n style={styles.spinner}\n />\n )}\n <Text style={styles.buttonText}>\n {children || label}\n {hasItems && ` (${state.items.length})`}\n </Text>\n </Pressable>\n\n {hasItems && (\n <View style={styles.statsContainer}>\n <Text style={styles.statsText}>\n Progress: {state.items.filter((i) => i.status === \"success\").length}\n /{state.items.length} uploaded\n </Text>\n <Text style={styles.statsText}>Overall: {state.totalProgress}%</Text>\n </View>\n )}\n\n {showProgress && hasItems && (\n <FlatList\n scrollEnabled={false}\n data={state.items}\n renderItem={renderItem}\n keyExtractor={(item) => item.id}\n style={styles.listContainer}\n contentContainerStyle={styles.listContent}\n ItemSeparatorComponent={() => <View style={styles.separator} />}\n />\n )}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n gap: 8,\n },\n button: {\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"center\",\n paddingVertical: 12,\n paddingHorizontal: 16,\n backgroundColor: \"#34C759\",\n borderRadius: 8,\n gap: 8,\n },\n buttonDisabled: {\n opacity: 0.6,\n },\n buttonText: {\n fontSize: 16,\n fontWeight: \"600\",\n color: \"#FFFFFF\",\n },\n spinner: {\n marginRight: 4,\n },\n statsContainer: {\n paddingVertical: 8,\n paddingHorizontal: 12,\n backgroundColor: \"#f5f5f5\",\n borderRadius: 4,\n gap: 4,\n },\n statsText: {\n fontSize: 12,\n color: \"#666666\",\n },\n listContainer: {\n maxHeight: 400,\n },\n listContent: {\n gap: 8,\n },\n itemContainer: {\n paddingHorizontal: 0,\n },\n separator: {\n height: 4,\n },\n});\n","import { FlatList, Pressable, StyleSheet, Text, View } from \"react-native\";\nimport type { UploadItem } from \"../types\";\nimport { UploadProgress } from \"./UploadProgress\";\n\nexport interface UploadListProps {\n /** List of upload items to display */\n items: UploadItem[];\n /** Callback when remove item is pressed */\n onRemove?: (id: string) => void;\n /** Callback when item is pressed */\n onItemPress?: (item: UploadItem) => void;\n /** Whether to show remove button */\n showRemoveButton?: boolean;\n}\n\n/**\n * Component to display a list of upload items with individual progress\n * Shows status indicators and allows removal of items\n */\nexport function UploadList({\n items,\n onRemove,\n onItemPress,\n showRemoveButton = true,\n}: UploadListProps) {\n const renderItem = ({ item }: { item: UploadItem }) => (\n <Pressable\n style={[\n styles.itemContainer,\n { borderLeftColor: getStatusColor(item.progress.state) },\n ]}\n onPress={() => onItemPress?.(item)}\n >\n <View style={styles.itemContent}>\n {item.file.status === \"success\" && (\n <View style={styles.itemHeader}>\n <Text style={styles.fileName} numberOfLines={1}>\n {item.file.data.name}\n </Text>\n <Text style={styles.fileSize}>\n {getFileSizeDisplay(item.file.data.size)}\n </Text>\n </View>\n )}\n {item.file.status === \"error\" && (\n <Text style={styles.errorText}>{item.progress.error?.message}</Text>\n )}\n <View style={styles.progressWrapper}>\n <UploadProgress\n state={{\n status:\n item.progress.state === \"pending\"\n ? \"idle\"\n : item.progress.state === \"cancelled\"\n ? \"aborted\"\n : item.progress.state,\n progress: item.progress.progress,\n bytesUploaded: item.progress.uploadedBytes,\n totalBytes: item.progress.totalBytes,\n error: item.progress.error || null,\n result: (item.result as any) || null,\n }}\n />\n </View>\n </View>\n {showRemoveButton &&\n item.progress.state !== \"uploading\" &&\n item.progress.state !== \"pending\" && (\n <Pressable\n style={styles.removeButton}\n onPress={() => onRemove?.(item.id)}\n hitSlop={{ top: 8, right: 8, bottom: 8, left: 8 }}\n >\n <Text style={styles.removeButtonText}>✕</Text>\n </Pressable>\n )}\n </Pressable>\n );\n\n if (items.length === 0) {\n return (\n <View style={styles.emptyContainer}>\n <Text style={styles.emptyText}>No uploads</Text>\n </View>\n );\n }\n\n return (\n <View style={styles.container}>\n <View style={styles.headerRow}>\n <Text style={styles.headerText}>Uploads ({items.length})</Text>\n <Text style={styles.headerSubtext}>\n {items.filter((i) => i.progress.state === \"success\").length} complete\n </Text>\n </View>\n <FlatList\n scrollEnabled={false}\n data={items}\n renderItem={renderItem}\n keyExtractor={(item) => item.id}\n ItemSeparatorComponent={() => <View style={styles.separator} />}\n contentContainerStyle={styles.listContent}\n />\n </View>\n );\n}\n\n// Helper functions\nfunction getStatusColor(state: string): string {\n switch (state) {\n case \"success\":\n return \"#34C759\";\n case \"error\":\n case \"cancelled\":\n return \"#FF3B30\";\n case \"uploading\":\n case \"pending\":\n return \"#007AFF\";\n default:\n return \"#999999\";\n }\n}\n\nfunction getFileSizeDisplay(bytes: number): string {\n if (bytes === 0) return \"0 B\";\n const k = 1024;\n const sizes = [\"B\", \"KB\", \"MB\", \"GB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${Math.round((bytes / k ** i) * 10) / 10} ${sizes[i]}`;\n}\n\nconst styles = StyleSheet.create({\n container: {\n gap: 8,\n },\n headerRow: {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n paddingHorizontal: 12,\n paddingVertical: 8,\n backgroundColor: \"#f9f9f9\",\n borderRadius: 4,\n },\n headerText: {\n fontSize: 16,\n fontWeight: \"600\",\n color: \"#333333\",\n },\n errorText: {\n fontSize: 14,\n color: \"#FF3B30\",\n },\n headerSubtext: {\n fontSize: 14,\n color: \"#666666\",\n },\n listContent: {\n gap: 8,\n },\n itemContainer: {\n flexDirection: \"row\",\n alignItems: \"center\",\n paddingVertical: 8,\n paddingHorizontal: 12,\n borderLeftWidth: 4,\n backgroundColor: \"#f5f5f5\",\n borderRadius: 4,\n gap: 8,\n },\n itemContent: {\n flex: 1,\n gap: 6,\n },\n itemHeader: {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n },\n fileName: {\n fontSize: 14,\n fontWeight: \"500\",\n color: \"#333333\",\n flex: 1,\n },\n fileSize: {\n fontSize: 12,\n color: \"#999999\",\n marginLeft: 8,\n },\n progressWrapper: {\n marginTop: 2,\n },\n removeButton: {\n width: 32,\n height: 32,\n justifyContent: \"center\",\n alignItems: \"center\",\n borderRadius: 16,\n backgroundColor: \"#FFE5E5\",\n },\n removeButtonText: {\n fontSize: 16,\n fontWeight: \"600\",\n color: \"#FF3B30\",\n },\n separator: {\n height: 4,\n },\n emptyContainer: {\n paddingVertical: 24,\n paddingHorizontal: 12,\n backgroundColor: \"#f5f5f5\",\n borderRadius: 4,\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n emptyText: {\n fontSize: 14,\n color: \"#999999\",\n fontStyle: \"italic\",\n },\n});\n"],"mappings":"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,UACjB,aAAc,EACf,CACD,WAAY,CACV,SAAU,GACV,WAAY,MACZ,MAAO,UACR,CACD,UAAW,CACT,SAAU,GACV,MAAO,UACR,CACD,cAAe,CACb,SAAU,GACV,MAAO,UACR,CACD,YAAa,CACX,IAAK,EACN,CACD,cAAe,CACb,cAAe,MACf,WAAY,SACZ,gBAAiB,EACjB,kBAAmB,GACnB,gBAAiB,EACjB,gBAAiB,UACjB,aAAc,EACd,IAAK,EACN,CACD,YAAa,CACX,KAAM,EACN,IAAK,EACN,CACD,WAAY,CACV,cAAe,MACf,eAAgB,gBAChB,WAAY,SACb,CACD,SAAU,CACR,SAAU,GACV,WAAY,MACZ,MAAO,UACP,KAAM,EACP,CACD,SAAU,CACR,SAAU,GACV,MAAO,UACP,WAAY,EACb,CACD,gBAAiB,CACf,UAAW,EACZ,CACD,aAAc,CACZ,MAAO,GACP,OAAQ,GACR,eAAgB,SAChB,WAAY,SACZ,aAAc,GACd,gBAAiB,UAClB,CACD,iBAAkB,CAChB,SAAU,GACV,WAAY,MACZ,MAAO,UACR,CACD,UAAW,CACT,OAAQ,EACT,CACD,eAAgB,CACd,gBAAiB,GACjB,kBAAmB,GACnB,gBAAiB,UACjB,aAAc,EACd,WAAY,SACZ,eAAgB,SACjB,CACD,UAAW,CACT,SAAU,GACV,MAAO,UACP,UAAW,SACZ,CACF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uploadista/react-native-core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13-beta.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Core React Native client for Uploadista",
|
|
6
6
|
"license": "MIT",
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"uuid": "^13.0.0",
|
|
17
17
|
"js-base64": "^3.7.7",
|
|
18
|
-
"@uploadista/core": "0.0.
|
|
19
|
-
"@uploadista/client-core": "0.0.
|
|
18
|
+
"@uploadista/core": "0.0.13-beta.1",
|
|
19
|
+
"@uploadista/client-core": "0.0.13-beta.1"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
22
22
|
"react": ">=16.8.0",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/react": ">=18.0.0",
|
|
33
33
|
"tsdown": "0.16.0",
|
|
34
|
-
"@uploadista/typescript-config": "0.0.
|
|
34
|
+
"@uploadista/typescript-config": "0.0.13-beta.1"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "tsdown",
|
|
@@ -221,9 +221,7 @@ export function useMultiUpload(options: UseMultiUploadOptions = {}) {
|
|
|
221
221
|
|
|
222
222
|
onError: (error: Error) => {
|
|
223
223
|
const updatedItems = itemsRef.current.map((i) =>
|
|
224
|
-
i.id === item.id
|
|
225
|
-
? { ...i, status: "error" as const, error }
|
|
226
|
-
: i,
|
|
224
|
+
i.id === item.id ? { ...i, status: "error" as const, error } : i,
|
|
227
225
|
);
|
|
228
226
|
updateAggregateStats(updatedItems);
|
|
229
227
|
|