UNPKG

health-ecosystem-file-upload

Version:

File upload library for Health Ecosystem applications with improved Next.js 15+ compatibility

4,709 lines 217 kB
'use strict';

var React = require('react');
var axios = require('axios');
var jsxRuntime = require('react/jsx-runtime');
var lucideReact = require('lucide-react');
var ReactDOM = require('react-dom');
var clsx = require('clsx');
var tailwindMerge = require('tailwind-merge');
var classVarianceAuthority = require('class-variance-authority');

function _interopNamespaceDefault(e) {
    var n = Object.create(null);
    if (e) {
        Object.keys(e).forEach(function (k) {
            if (k !== 'default') {
                var d = Object.getOwnPropertyDescriptor(e, k);
                Object.defineProperty(n, k, d.get ? d : {
                    enumerable: true,
                    get: function () { return e[k]; }
                });
            }
        });
    }
    n.default = e;
    return Object.freeze(n);
}

var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
var ReactDOM__namespace = /*#__PURE__*/_interopNamespaceDefault(ReactDOM);

/**
 * React Compatibility Layer
 * Handles differences between React versions (18, 19+)
 */
// Check React version
const REACT_VERSION = React.version;
const IS_REACT_19_PLUS = parseInt(React.version.split('.')[0]) >= 19;
const IS_REACT_18 = React.version.startsWith('18.');
// Export compatibility info
const REACT_COMPAT_INFO = {
    version: REACT_VERSION,
    isReact19Plus: IS_REACT_19_PLUS,
    isReact18: IS_REACT_18,
    supportsNewJSXTransform: true, // Both 18 and 19+ support this
    supportsConcurrentFeatures: true
};

/**
 * File Upload Client
 * Production-ready client for Health Ecosystem file uploads
 */
class FileUploadClient {
    constructor(config) {
        this.cancelTokens = new Map();
        const defaultAllowedTypes = [
            'image/jpeg', 'image/png', 'image/gif', 'image/webp',
            'application/pdf', 'application/msword',
            'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            'text/plain', 'text/csv'
        ];
        this.config = {
            maxFileSize: config.maxFileSize || 50 * 1024 * 1024, // 50MB
            allowedTypes: config.allowedTypes || defaultAllowedTypes,
            timeout: config.timeout || 30000, // 30 seconds
            enableRetry: config.enableRetry ?? true,
            maxRetries: config.maxRetries || 3,
            baseUrl: config.baseUrl,
            authToken: config.authToken
        };
        this.client = axios.create({
            baseURL: this.config.baseUrl,
            timeout: this.config.timeout,
            headers: {
                'Authorization': `Bearer ${this.config.authToken}`
            }
        });
        // Add response interceptor for error handling
        this.client.interceptors.response.use((response) => response, (error) => this.handleError(error));
    }
    /**
     * Upload a single file
     */
    async uploadFile(file, options = { category: 'other' }, callbacks) {
        const uploadId = this.generateUploadId();
        try {
            // Validate file
            this.validateFile(file);
            // Create cancel token
            const cancelToken = axios.CancelToken.source();
            this.cancelTokens.set(uploadId, cancelToken);
            // Prepare form data
            const formData = new FormData();
            formData.append('file', file);
            formData.append('file_category', options.category || 'other');
            if (options.entityType) {
                formData.append('associated_entity_type', options.entityType);
            }
            if (options.entityId) {
                formData.append('associated_entity_id', options.entityId);
            }
            formData.append('is_public', String(options.isPublic || false));
            if (options.metadata) {
                formData.append('metadata', options.metadata);
            }
            // Call onStart callback
            options.onStart?.();
            // Upload with progress tracking
            const response = await this.client.post('/upload', formData, {
                headers: {
                    'Content-Type': 'multipart/form-data'
                },
                cancelToken: cancelToken.token,
                onUploadProgress: (progressEvent) => {
                    if (progressEvent.total) {
                        const progress = Math.round((progressEvent.loaded * 100) / progressEvent.total);
                        options.onProgress?.(progress);
                        callbacks?.onProgress?.(progress);
                    }
                }
            });
            // Clean up cancel token
            this.cancelTokens.delete(uploadId);
            // Parse response
            const result = this.parseUploadResponse(response.data);
            // Call success callback
            options.onSuccess?.(result);
            return result;
        }
        catch (error) {
            // Clean up cancel token
            this.cancelTokens.delete(uploadId);
            const uploadError = this.createUploadError(error);
            // Call error callback
            options.onError?.(uploadError);
            throw uploadError;
        }
    }
    /**
     * Upload multiple files
     */
    async uploadFiles(files, options) {
        const results = [];
        const errors = [];
        for (let i = 0; i < files.length; i++) {
            try {
                const fileOptions = {
                    ...options,
                    onProgress: (progress) => {
                        const overallProgress = ((i * 100) + progress) / files.length;
                        options.onProgress?.(Math.round(overallProgress));
                    }
                };
                const result = await this.uploadFile(files[i], fileOptions);
                results.push(result);
            }
            catch (error) {
                errors.push(error);
            }
        }
        if (errors.length > 0 && results.length === 0) {
            throw new Error(`All uploads failed: ${errors.map(e => e.message).join(', ')}`);
        }
        return results;
    }
    /**
     * Upload file from URL
     * Downloads the file from the provided URL and uploads it to the server
     */
    async uploadFromUrl(url, options) {
        const uploadId = this.generateUploadId();
        try {
            // Validate URL
            if (!this.isValidUrl(url)) {
                throw new Error('Invalid URL provided');
            }
            // Call start callback
            options.onStart?.();
            // Create cancel token
            const cancelToken = axios.CancelToken.source();
            this.cancelTokens.set(uploadId, cancelToken);
            // Step 1: Download file from URL with progress tracking
            options.onProgress?.(10); // Initial progress
            const fileResponse = await axios.get(url, {
                responseType: 'blob',
                cancelToken: cancelToken.token,
                onDownloadProgress: (progressEvent) => {
                    if (progressEvent.total) {
                        // Use 10-60% for download progress
                        const downloadProgress = Math.round((progressEvent.loaded * 50) / progressEvent.total) + 10;
                        options.onProgress?.(downloadProgress);
                    }
                }
            });
            // Step 2: Extract filename and content type
            const filename = options.filename || this.extractFilenameFromUrl(url) || 'downloaded-file';
            const contentType = fileResponse.headers['content-type'] || 'application/octet-stream';
            // Create File object from blob
            const file = new File([fileResponse.data], filename, { type: contentType });
            // Validate file size
            if (file.size > this.config.maxFileSize) {
                throw new Error(`File size (${file.size} bytes) exceeds maximum allowed size (${this.config.maxFileSize} bytes)`);
            }
            // Validate file type
            if (!this.isAllowedFileType(file.type)) {
                throw new Error(`File type ${file.type} is not allowed`);
            }
            options.onProgress?.(70); // Download complete, starting upload
            // Step 3: Upload the file
            const formData = new FormData();
            formData.append('file', file);
            // Add metadata
            if (options.category)
                formData.append('file_category', options.category);
            if (options.entityType)
                formData.append('entity_type', options.entityType);
            if (options.entityId)
                formData.append('entity_id', options.entityId);
            if (options.isPublic !== undefined)
                formData.append('is_public', options.isPublic.toString());
            if (options.metadata)
                formData.append('metadata', options.metadata);
            // Add source URL as metadata
            const sourceMetadata = { source_url: url, upload_method: 'url' };
            const existingMetadata = options.metadata ? JSON.parse(options.metadata) : {};
            formData.append('metadata', JSON.stringify({ ...existingMetadata, ...sourceMetadata }));
            const response = await this.client.post('/upload', formData, {
                headers: {
                    'Content-Type': 'multipart/form-data',
                },
                cancelToken: cancelToken.token,
                onUploadProgress: (progressEvent) => {
                    if (progressEvent.total) {
                        // Use 70-100% for upload progress
                        const uploadProgress = Math.round((progressEvent.loaded * 30) / progressEvent.total) + 70;
                        options.onProgress?.(uploadProgress);
                    }
                }
            });
            // Clean up cancel token
            this.cancelTokens.delete(uploadId);
            // Parse response
            const result = this.parseUploadResponse(response.data);
            // Call success callback
            options.onSuccess?.(result);
            return result;
        }
        catch (error) {
            // Clean up cancel token
            this.cancelTokens.delete(uploadId);
            if (axios.isCancel(error)) {
                const cancelError = {
                    code: 'UPLOAD_CANCELLED',
                    message: 'URL upload was cancelled',
                    status: 0
                };
                options.onError?.(cancelError);
                throw cancelError;
            }
            const uploadError = this.createUploadError(error);
            // Call error callback
            options.onError?.(uploadError);
            throw uploadError;
        }
    }
    /**
     * Get file metadata
     */
    async getFileMetadata(fileId) {
        try {
            const response = await this.client.get(`/files/${fileId}`);
            return this.parseFileMetadata(response.data.data);
        }
        catch (error) {
            throw this.createUploadError(error);
        }
    }
    /**
     * Get download URL for a file
     */
    getDownloadUrl(fileId) {
        return `${this.config.baseUrl}/files/${fileId}/download`;
    }
    /**
     * Get thumbnail URL for an image
     */
    getThumbnailUrl(fileId) {
        return `${this.config.baseUrl}/files/${fileId}/thumbnail`;
    }
    /**
     * Get preview URL for a file with optional transformations
     * @param previewUrl The preview URL from the file response
     * @param options Optional transformation parameters
     * @returns Full URL to the preview
     */
    getPreviewUrl(previewUrl, options) {
        if (!previewUrl)
            return '';
        const baseUrl = `${this.config.baseUrl}${previewUrl}`;
        const params = new URLSearchParams();
        if (options?.thumbnail)
            params.append('thumbnail', 'true');
        if (options?.width)
            params.append('width', options.width.toString());
        if (options?.height)
            params.append('height', options.height.toString());
        if (options?.quality)
            params.append('quality', options.quality.toString());
        if (options?.format)
            params.append('format', options.format);
        const queryString = params.toString();
        return queryString ? `${baseUrl}?${queryString}` : baseUrl;
    }
    /**
     * Delete a file
     */
    async deleteFile(fileId) {
        try {
            await this.client.delete(`/files/${fileId}`);
        }
        catch (error) {
            throw this.createUploadError(error);
        }
    }
    /**
     * List files with optional filters - Updated to match backend API structure
     */
    async listFiles(options) {
        try {
            const params = new URLSearchParams();
            // Set default pagination
            params.append('skip', (options?.skip || 0).toString());
            params.append('limit', (options?.limit || 100).toString());
            if (options?.category)
                params.append('file_category', options.category);
            if (options?.entityType)
                params.append('associated_entity_type', options.entityType);
            if (options?.entityId)
                params.append('associated_entity_id', options.entityId);
            if (options?.isPublic !== undefined)
                params.append('is_public', options.isPublic.toString());
            // Use the correct endpoint: /files (since baseUrl already includes /api/files)
            const response = await this.client.get(`/files?${params.toString()}`);
            // Backend returns array directly, not wrapped in data object
            const files = Array.isArray(response.data) ? response.data : (response.data.data || []);
            return files.map((file) => this.parseFileMetadata(file));
        }
        catch (error) {
            throw this.createUploadError(error);
        }
    }
    /**
     * Cancel an ongoing upload
     */
    cancelUpload(uploadId) {
        if (uploadId && this.cancelTokens.has(uploadId)) {
            this.cancelTokens.get(uploadId)?.cancel('Upload cancelled by user');
            this.cancelTokens.delete(uploadId);
        }
        else {
            // Cancel all uploads
            this.cancelTokens.forEach((cancelToken) => {
                cancelToken.cancel('Upload cancelled by user');
            });
            this.cancelTokens.clear();
        }
    }
    /**
     * Update authentication token
     */
    updateAuthToken(token) {
        this.config.authToken = token;
        this.client.defaults.headers['Authorization'] = `Bearer ${token}`;
    }
    /**
     * Validate file before upload
     */
    validateFile(file) {
        // Check file size
        if (file.size > this.config.maxFileSize) {
            throw new Error(`File size (${this.formatFileSize(file.size)}) exceeds maximum allowed size (${this.formatFileSize(this.config.maxFileSize)})`);
        }
        // Check file type - ensure allowedTypes is an array and has items
        if (this.config.allowedTypes && Array.isArray(this.config.allowedTypes) && this.config.allowedTypes.length > 0) {
            const isAllowed = this.config.allowedTypes.some(allowedType => {
                // Handle wildcard patterns like "image/*"
                if (allowedType.includes('*')) {
                    const baseType = allowedType.split('/')[0];
                    return file.type.startsWith(baseType + '/');
                }
                // Handle exact matches
                return allowedType === file.type;
            });
            if (!isAllowed) {
                throw new Error(`File type '${file.type}' is not allowed. Allowed types: ${this.config.allowedTypes.join(', ')}`);
            }
        }
    }
    /**
     * Parse upload response
     */
    parseUploadResponse(data) {
        const responseData = data.data || data;
        return {
            id: responseData.file_id || responseData.id || `file-${Date.now()}`,
            fileId: responseData.file_id || responseData.id || `file-${Date.now()}`,
            originalFilename: responseData.original_filename || responseData.originalFilename,
            storedFilename: responseData.stored_filename || responseData.storedFilename,
            filename: responseData.stored_filename || responseData.storedFilename || responseData.filename,
            fileSize: responseData.file_size || responseData.fileSize || 0,
            mimeType: responseData.mime_type || responseData.mimeType || 'application/octet-stream',
            category: responseData.file_category || responseData.category || 'other',
            downloadUrl: responseData.download_url || responseData.downloadUrl || this.getDownloadUrl(responseData.file_id || responseData.id),
            thumbnailUrl: responseData.thumbnail_url || responseData.thumbnailUrl || ((responseData.mime_type || responseData.mimeType)?.startsWith('image/') ?
                this.getThumbnailUrl(responseData.file_id || responseData.id) :
                undefined),
            previewUrl: responseData.preview_url || responseData.previewUrl,
            uploadedAt: responseData.uploaded_at || responseData.uploadedAt || new Date().toISOString(),
            isPublic: responseData.is_public || responseData.isPublic || false
        };
    }
    /**
     * Parse file metadata response - Updated to match backend structure
     */
    parseFileMetadata(data) {
        return {
            id: data.id,
            originalFilename: data.original_filename,
            fileSize: data.file_size,
            mimeType: data.mime_type,
            category: data.file_category,
            uploadedBy: data.uploaded_by,
            entityType: data.associated_entity_type,
            entityId: data.associated_entity_id,
            isPublic: data.is_public,
            createdAt: data.created_at,
            downloadUrl: data.download_url,
            thumbnailUrl: data.thumbnail_url,
            previewUrl: data.preview_url
        };
    }
    /**
     * Create standardized upload error
     */
    createUploadError(error) {
        if (axios.isCancel(error)) {
            return {
                code: 'UPLOAD_CANCELLED',
                message: 'Upload was cancelled',
                status: 0
            };
        }
        if (error.response) {
            return {
                code: error.response.data?.code || 'HTTP_ERROR',
                message: error.response.data?.detail || error.response.data?.message || error.message,
                status: error.response.status,
                details: error.response.data
            };
        }
        if (error.request) {
            return {
                code: 'NETWORK_ERROR',
                message: 'Network error occurred during upload',
                details: error.request
            };
        }
        return {
            code: 'UNKNOWN_ERROR',
            message: error.message || 'An unknown error occurred',
            details: error
        };
    }
    /**
     * Handle axios errors with retry logic
     */
    async handleError(error) {
        if (this.config.enableRetry && this.shouldRetry(error)) ;
        return Promise.reject(error);
    }
    /**
     * Determine if error should be retried
     */
    shouldRetry(error) {
        if (!error.response)
            return true; // Network errors
        const status = error.response.status;
        return status >= 500 || status === 429; // Server errors or rate limiting
    }
    /**
     * Generate unique upload ID
     */
    generateUploadId() {
        return `upload_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    }
    /**
     * Format file size for display
     */
    formatFileSize(bytes) {
        if (bytes === 0)
            return '0 Bytes';
        const k = 1024;
        const sizes = ['Bytes', 'KB', 'MB', 'GB'];
        const i = Math.floor(Math.log(bytes) / Math.log(k));
        return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
    }
    /**
     * Validate URL format
     */
    isValidUrl(url) {
        try {
            const urlObj = new URL(url);
            return urlObj.protocol === 'http:' || urlObj.protocol === 'https:';
        }
        catch {
            return false;
        }
    }
    /**
     * Extract filename from URL
     */
    extractFilenameFromUrl(url) {
        try {
            const urlObj = new URL(url);
            const pathname = urlObj.pathname;
            const filename = pathname.split('/').pop() || '';
            // If no filename or just extension, generate a default name
            if (!filename || filename.startsWith('.')) {
                const extension = this.getFileExtensionFromUrl(url);
                return `downloaded-file${extension ? '.' + extension : ''}`;
            }
            return filename;
        }
        catch {
            return 'downloaded-file';
        }
    }
    /**
     * Get file extension from URL or content type
     */
    getFileExtensionFromUrl(url) {
        try {
            const urlObj = new URL(url);
            const pathname = urlObj.pathname;
            const lastDot = pathname.lastIndexOf('.');
            if (lastDot > 0) {
                return pathname.substring(lastDot + 1).toLowerCase();
            }
        }
        catch {
            // Ignore URL parsing errors
        }
        return '';
    }
    /**
     * Check if file type is allowed
     */
    isAllowedFileType(mimeType) {
        if (!this.config.allowedTypes || this.config.allowedTypes.length === 0) {
            return true; // No restrictions
        }
        return this.config.allowedTypes.some(allowedType => {
            if (allowedType === '*/*')
                return true;
            // Handle wildcard patterns like "image/*"
            if (allowedType.includes('*')) {
                const baseType = allowedType.split('/')[0];
                return mimeType.startsWith(baseType + '/');
            }
            // Handle exact matches
            return allowedType === mimeType;
        });
    }
}

const FileUploadLibrary = ({ config, options = {}, onFileSelect, multiple = false, accept = "*/*", className = "", style = {} }) => {
    const [client] = React.useState(() => new FileUploadClient(config));
    const [files, setFiles] = React.useState([]);
    const [loading, setLoading] = React.useState(true);
    const [uploadState, setUploadState] = React.useState({
        selectedFile: null,
        isUploading: false,
        uploadProgress: 0,
        error: null
    });
    // Load files from the library
    const loadFiles = React.useCallback(async () => {
        try {
            setLoading(true);
            const libraryFiles = await client.listFiles({
                skip: 0,
                limit: 100,
                ...options
            });
            setFiles(libraryFiles);
        }
        catch (error) {
            console.error('Failed to load files:', error);
            setUploadState(prev => ({ ...prev, error: 'Failed to load files' }));
        }
        finally {
            setLoading(false);
        }
    }, [client, options]);
    // Load files on component mount
    React.useEffect(() => {
        loadFiles();
    }, [loadFiles]);
    // Handle file selection for upload
    const handleFileSelect = (event) => {
        const file = event.target.files?.[0];
        if (file) {
            setUploadState(prev => ({
                ...prev,
                selectedFile: file,
                error: null
            }));
        }
    };
    // Handle file upload
    const handleUpload = async () => {
        if (!uploadState.selectedFile)
            return;
        try {
            setUploadState(prev => ({
                ...prev,
                isUploading: true,
                uploadProgress: 0,
                error: null
            }));
            const uploadOptions = {
                ...options,
                onProgress: (progress) => {
                    setUploadState(prev => ({ ...prev, uploadProgress: progress }));
                }
            };
            await client.uploadFile(uploadState.selectedFile, uploadOptions);
            // Reset upload state and reload files
            setUploadState({
                selectedFile: null,
                isUploading: false,
                uploadProgress: 0,
                error: null
            });
            // Reload the library to show the new file
            await loadFiles();
        }
        catch (error) {
            setUploadState(prev => ({
                ...prev,
                isUploading: false,
                error: error.message || 'Upload failed'
            }));
        }
    };
    // Handle file deletion
    const handleDelete = async (fileId) => {
        if (!confirm('Are you sure you want to delete this file?'))
            return;
        try {
            await client.deleteFile(fileId);
            await loadFiles(); // Reload files after deletion
        }
        catch (error) {
            alert('Failed to delete file: ' + (error.message || 'Unknown error'));
        }
    };
    // Handle file selection from library
    const handleLibraryFileSelect = (file) => {
        onFileSelect?.(file);
    };
    // Handle preview
    const handlePreview = (file) => {
        if (file.previewUrl) {
            const fullPreviewUrl = client.getPreviewUrl(file.previewUrl);
            window.open(fullPreviewUrl, '_blank');
        }
        else if (file.downloadUrl) {
            window.open(`${config.baseUrl}${file.downloadUrl}`, '_blank');
        }
    };
    // Cancel file selection
    const cancelSelection = () => {
        setUploadState(prev => ({
            ...prev,
            selectedFile: null,
            error: null
        }));
    };
    if (loading) {
        return (jsxRuntime.jsx("div", { className: `file-upload-library ${className}`, style: style, children: jsxRuntime.jsxs("div", { className: "loading-state", children: [jsxRuntime.jsx("div", { className: "spinner" }), jsxRuntime.jsx("p", { children: "Loading files..." })] }) }));
    }
    return (jsxRuntime.jsxs("div", { className: `file-upload-library ${className}`, style: style, children: [jsxRuntime.jsxs("div", { className: "upload-section", children: [!uploadState.selectedFile ? (
                    // File selection area
                    jsxRuntime.jsxs("div", { className: "file-select-area", children: [jsxRuntime.jsx("input", { type: "file", id: "file-input", accept: accept, multiple: multiple, onChange: handleFileSelect, style: { display: 'none' } }), jsxRuntime.jsxs("label", { htmlFor: "file-input", className: "file-select-button", children: [jsxRuntime.jsx("div", { className: "upload-icon", children: "\uD83D\uDCC1" }), jsxRuntime.jsx("p", { children: "Click to select a file to upload" }), jsxRuntime.jsx("small", { children: "or drag and drop files here" })] })] })) : (
                    // Upload confirmation area
                    jsxRuntime.jsxs("div", { className: "upload-confirmation", children: [jsxRuntime.jsxs("div", { className: "selected-file-info", children: [jsxRuntime.jsx("div", { className: "file-icon", children: "\uD83D\uDCC4" }), jsxRuntime.jsxs("div", { className: "file-details", children: [jsxRuntime.jsx("h4", { children: uploadState.selectedFile.name }), jsxRuntime.jsxs("p", { children: [(uploadState.selectedFile.size / 1024 / 1024).toFixed(2), " MB"] })] })] }), uploadState.isUploading ? (jsxRuntime.jsxs("div", { className: "upload-progress", children: [jsxRuntime.jsx("div", { className: "progress-bar", children: jsxRuntime.jsx("div", { className: "progress-fill", style: { width: `${uploadState.uploadProgress}%` } }) }), jsxRuntime.jsxs("p", { children: [uploadState.uploadProgress, "% uploaded"] })] })) : (jsxRuntime.jsxs("div", { className: "upload-actions", children: [jsxRuntime.jsx("button", { className: "upload-button primary", onClick: handleUpload, children: "Upload File" }), jsxRuntime.jsx("button", { className: "cancel-button secondary", onClick: cancelSelection, children: "Cancel" })] }))] })), uploadState.error && (jsxRuntime.jsx("div", { className: "error-message", children: uploadState.error }))] }), jsxRuntime.jsxs("div", { className: "file-library", children: [jsxRuntime.jsx("h3", { children: "File Library" }), files.length === 0 ? (jsxRuntime.jsx("div", { className: "empty-state", children: jsxRuntime.jsx("p", { children: "No files uploaded yet" }) })) : (jsxRuntime.jsx("div", { className: "file-grid", children: files.map((file) => (jsxRuntime.jsxs("div", { className: "file-item", children: [jsxRuntime.jsxs("div", { className: "file-thumbnail", children: [file.thumbnailUrl ? (jsxRuntime.jsx("img", { src: `${config.baseUrl}${file.thumbnailUrl}`, alt: file.originalFilename, onError: (e) => {
                                                // Fallback to file type icon if thumbnail fails
                                                const target = e.target;
                                                target.style.display = 'none';
                                                target.nextElementSibling?.classList.remove('hidden');
                                            } })) : null, jsxRuntime.jsx("div", { className: `file-type-icon ${file.thumbnailUrl ? 'hidden' : ''}`, children: getFileTypeIcon(file.mimeType) })] }), jsxRuntime.jsxs("div", { className: "file-info", children: [jsxRuntime.jsx("h4", { className: "file-name", title: file.originalFilename, children: file.originalFilename }), jsxRuntime.jsxs("p", { className: "file-size", children: [(file.fileSize / 1024 / 1024).toFixed(2), " MB"] }), jsxRuntime.jsx("p", { className: "file-date", children: new Date(file.createdAt).toLocaleDateString() })] }), jsxRuntime.jsxs("div", { className: "file-actions", children: [jsxRuntime.jsx("button", { className: "action-button select", onClick: () => handleLibraryFileSelect(file), title: "Select this file", children: "\u2713" }), jsxRuntime.jsx("button", { className: "action-button preview", onClick: () => handlePreview(file), title: "Preview file", children: "\uD83D\uDC41" }), jsxRuntime.jsx("button", { className: "action-button delete", onClick: () => handleDelete(file.id), title: "Delete file", children: "\uD83D\uDDD1" })] })] }, file.id))) }))] }), jsxRuntime.jsx("style", { dangerouslySetInnerHTML: {
                    __html: `
        .file-upload-library {
          max-width: 800px;
          margin: 0 auto;
          padding: 20px;
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
        }

        .loading-state {
          text-align: center;
          padding: 40px;
        }

        .spinner {
          width: 40px;
          height: 40px;
          border: 4px solid #f3f3f3;
          border-top: 4px solid #007bff;
          border-radius: 50%;
          animation: spin 1s linear infinite;
          margin: 0 auto 20px;
        }

        @keyframes spin {
          0% { transform: rotate(0deg); }
          100% { transform: rotate(360deg); }
        }

        .upload-section {
          margin-bottom: 30px;
          padding: 20px;
          border: 2px dashed #ddd;
          border-radius: 8px;
          background: #fafafa;
        }

        .file-select-area {
          text-align: center;
        }

        .file-select-button {
          display: block;
          padding: 40px;
          cursor: pointer;
          transition: background-color 0.2s;
        }

        .file-select-button:hover {
          background-color: #f0f0f0;
        }

        .upload-icon {
          font-size: 48px;
          margin-bottom: 16px;
        }

        .upload-confirmation {
          display: flex;
          align-items: center;
          gap: 20px;
        }

        .selected-file-info {
          display: flex;
          align-items: center;
          gap: 12px;
          flex: 1;
        }

        .file-icon {
          font-size: 32px;
        }

        .file-details h4 {
          margin: 0 0 4px 0;
          font-size: 16px;
        }

        .file-details p {
          margin: 0;
          color: #666;
          font-size: 14px;
        }

        .upload-progress {
          flex: 1;
        }

        .progress-bar {
          width: 100%;
          height: 8px;
          background-color: #e0e0e0;
          border-radius: 4px;
          overflow: hidden;
          margin-bottom: 8px;
        }

        .progress-fill {
          height: 100%;
          background-color: #007bff;
          transition: width 0.3s ease;
        }

        .upload-actions {
          display: flex;
          gap: 12px;
        }

        .upload-button, .cancel-button {
          padding: 10px 20px;
          border: none;
          border-radius: 6px;
          cursor: pointer;
          font-size: 14px;
          font-weight: 500;
          transition: background-color 0.2s;
        }

        .upload-button.primary {
          background-color: #007bff;
          color: white;
        }

        .upload-button.primary:hover {
          background-color: #0056b3;
        }

        .cancel-button.secondary {
          background-color: #6c757d;
          color: white;
        }

        .cancel-button.secondary:hover {
          background-color: #545b62;
        }

        .error-message {
          margin-top: 12px;
          padding: 12px;
          background-color: #f8d7da;
          color: #721c24;
          border: 1px solid #f5c6cb;
          border-radius: 4px;
        }

        .file-library h3 {
          margin-bottom: 20px;
          color: #333;
        }

        .empty-state {
          text-align: center;
          padding: 40px;
          color: #666;
        }

        .file-grid {
          display: grid;
          grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
          gap: 20px;
        }

        .file-item {
          border: 1px solid #ddd;
          border-radius: 8px;
          padding: 16px;
          background: white;
          transition: box-shadow 0.2s;
        }

        .file-item:hover {
          box-shadow: 0 4px 12px rgba(0,0,0,0.1);
        }

        .file-thumbnail {
          width: 100%;
          height: 120px;
          display: flex;
          align-items: center;
          justify-content: center;
          background: #f8f9fa;
          border-radius: 4px;
          margin-bottom: 12px;
          overflow: hidden;
        }

        .file-thumbnail img {
          max-width: 100%;
          max-height: 100%;
          object-fit: cover;
        }

        .file-type-icon {
          font-size: 48px;
          opacity: 0.5;
        }

        .hidden {
          display: none;
        }

        .file-info {
          margin-bottom: 12px;
        }

        .file-name {
          margin: 0 0 4px 0;
          font-size: 14px;
          font-weight: 500;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
        }

        .file-size, .file-date {
          margin: 0;
          font-size: 12px;
          color: #666;
        }

        .file-actions {
          display: flex;
          gap: 8px;
          justify-content: center;
        }

        .action-button {
          width: 32px;
          height: 32px;
          border: 1px solid #ddd;
          background: white;
          border-radius: 4px;
          cursor: pointer;
          display: flex;
          align-items: center;
          justify-content: center;
          font-size: 14px;
          transition: all 0.2s;
        }

        .action-button:hover {
          background-color: #f8f9fa;
        }

        .action-button.select:hover {
          background-color: #d4edda;
          border-color: #28a745;
        }

        .action-button.preview:hover {
          background-color: #d1ecf1;
          border-color: #17a2b8;
        }

        .action-button.delete:hover {
          background-color: #f8d7da;
          border-color: #dc3545;
        }
        `
                } })] }));
};
// Helper function to get file type icon
function getFileTypeIcon(mimeType) {
    if (mimeType.startsWith('image/'))
        return '🖼️';
    if (mimeType.startsWith('video/'))
        return '🎥';
    if (mimeType.startsWith('audio/'))
        return '🎵';
    if (mimeType.includes('pdf'))
        return '📄';
    if (mimeType.includes('word') || mimeType.includes('document'))
        return '📝';
    if (mimeType.includes('excel') || mimeType.includes('spreadsheet'))
        return '📊';
    if (mimeType.includes('powerpoint') || mimeType.includes('presentation'))
        return '📽️';
    if (mimeType.includes('zip') || mimeType.includes('archive'))
        return '📦';
    return '📄';
}

const UPLOAD_SOURCES$1 = [
    {
        id: "device",
        name: "My Device",
        icon: lucideReact.Folder,
        description: "Upload from computer",
    },
    {
        id: "camera",
        name: "Camera",
        icon: lucideReact.Camera,
        description: "Take photo or video",
    },
    {
        id: "googledrive",
        name: "Google Drive",
        icon: lucideReact.Cloud,
        description: "Import from Google Drive",
    },
    {
        id: "dropbox",
        name: "Dropbox",
        icon: lucideReact.Cloud,
        description: "Import from Dropbox",
    },
    {
        id: "onedrive",
        name: "OneDrive",
        icon: lucideReact.Cloud,
        description: "Import from OneDrive",
    },
    {
        id: "url",
        name: "From URL",
        icon: lucideReact.Link,
        description: "Import from web URL",
    },
    {
        id: "instagram",
        name: "Instagram",
        icon: lucideReact.Image,
        description: "Import from Instagram",
    },
    {
        id: "facebook",
        name: "Facebook",
        icon: lucideReact.Globe,
        description: "Import from Facebook",
    },
];
const FileUploadWidget = ({ config, options = {}, isOpen, onClose, onFileSelect, onSuccess, onError, multiple = true, accept = "*/*", maxFileSize, title = "Upload Files", showLibrary = true, className = "", }) => {
    const [activeSource, setActiveSource] = React.useState("device");
    const [uploadingFiles, setUploadingFiles] = React.useState([]);
    const [libraryFiles, setLibraryFiles] = React.useState([]);
    const [selectedFiles, setSelectedFiles] = React.useState([]);
    const [isDragActive, setIsDragActive] = React.useState(false);
    const [isLoading, setIsLoading] = React.useState(false);
    const [urlInput, setUrlInput] = React.useState("");
    const fileInputRef = React.useRef(null);
    const cameraInputRef = React.useRef(null);
    const clientRef = React.useRef();
    const dragCounter = React.useRef(0);
    // Initialize client
    React.useEffect(() => {
        if (!clientRef.current) {
            clientRef.current = new FileUploadClient(config);
        }
    }, [config]);
    // Load library files when widget opens
    React.useEffect(() => {
        if (isOpen && showLibrary && clientRef.current) {
            loadLibraryFiles();
        }
    }, [isOpen, showLibrary]);
    const loadLibraryFiles = async () => {
        if (!clientRef.current)
            return;
        setIsLoading(true);
        try {
            const files = await clientRef.current.listFiles({
                limit: 50,
                isPublic: true,
            });
            // Convert FileMetadata to UploadResult format
            const uploadResults = files.map((file) => ({
                id: file.id,
                fileId: file.id,
                originalFilename: file.originalFilename,
                storedFilename: file.id, // Use ID as stored filename
                filename: file.id,
                fileSize: file.fileSize,
                mimeType: file.mimeType,
                category: file.category,
                downloadUrl: file.downloadUrl,
                thumbnailUrl: file.thumbnailUrl,
                uploadedAt: file.createdAt,
            }));
            setLibraryFiles(uploadResults);
        }
        catch (error) {
            console.error("Failed to load library files:", error);
        }
        finally {
            setIsLoading(false);
        }
    };
    const handleFileSelect = React.useCallback((event) => {
        const files = event.target.files;
        if (files && files.length > 0) {
            const fileArray = Array.from(files);
            uploadFiles(fileArray);
        }
        // Reset input
        if (event.target) {
            event.target.value = "";
        }
    }, []);
    const uploadFiles = async (files) => {
        if (!clientRef.current)
            return;
        const uploadingFilesList = files.map((file) => ({
            id: `${Date.now()}-${Math.random()}`,
            file,
            progress: 0,
            status: "uploading",
            preview: file.type.startsWith("image/")
                ? URL.createObjectURL(file)
                : undefined,
        }));
        setUploadingFiles((prev) => [...prev, ...uploadingFilesList]);
        const uploadPromises = uploadingFilesList.map(async (uploadingFile) => {
            try {
                const uploadOptions = {
                    category: "document",
                    isPublic: true,
                    ...options,
                    onProgress: (progress) => {
                        setUploadingFiles((prev) => prev.map((f) => f.id === uploadingFile.id ? { ...f, progress } : f));
                    },
                };
                const result = await clientRef.current.uploadFile(uploadingFile.file, uploadOptions);
                setUploadingFiles((prev) => prev.map((f) => f.id === uploadingFile.id
                    ? { ...f, status: "completed", result, progress: 100 }
                    : f));
                return result;
            }
            catch (error) {
                setUploadingFiles((prev) => prev.map((f) => f.id === uploadingFile.id
                    ? {
                        ...f,
                        status: "error",
                        error: error instanceof Error ? error.message : "Upload failed",
                    }
                    : f));
                throw error;
            }
        });
        try {
            const results = await Promise.all(uploadPromises);
            onSuccess?.(results);
            // Add to library
            setLibraryFiles((prev) => [...results, ...prev]);
            // Clear uploading files after delay
            setTimeout(() => {
                setUploadingFiles((prev) => prev.filter((f) => f.status === "uploading"));
            }, 2000);
        }
        catch (error) {
            onError?.(error instanceof Error ? error : new Error("Upload failed"));
        }
    };
    const handleUrlUpload = async () => {
        if (!urlInput.trim() || !clientRef.current)
            return;
        try {
            const response = await fetch(urlInput);
            const blob = await response.blob();
            const filename = urlInput.split("/").pop() || "url-file";
            const file = new File([blob], filename, { type: blob.type });
            await uploadFiles([file]);
            setUrlInput("");
        }
        catch (error) {
            onError?.(error instanceof Error ? error : new Error("URL upload failed"));
        }
    };
    const handleDragEnter = React.useCallback((e) => {
        e.preventDefault();
        e.stopPropagation();
        dragCounter.current++;
        if (e.dataTransfer.items && e.dataTransfer.items.length > 0) {
            setIsDragActive(true);
        }
    }, []);
    const handleDragLeave = React.useCallback((e) => {
        e.preventDefault();
        e.stopPropagation();
        dragCounter.current--;
        if (dragCounter.current === 0) {
            setIsDragActive(false);
        }
    }, []);
    const handleDragOver = React.useCallback((e) => {
        e.preventDefault();
        e.stopPropagation();
    }, []);
    const handleDrop = React.useCallback((e) => {
        e.preventDefault();
        e.stopPropagation();
        setIsDragActive(false);
        dragCounter.current = 0;
        const files = Array.from(e.dataTransfer.files);
        if (files.length > 0) {
            uploadFiles(files);
        }
    }, []);
    const handleLibraryFileSelect = (file) => {
        if (multiple) {
            setSelectedFiles((prev) => {
                const exists = prev.find((f) => f.fileId === file.fileId);
                if (exists) {
                    return prev.filter((f) => f.fileId !== file.fileId);
                }
                return [...prev, file];
            });
        }
        else {
            setSelectedFiles([file]);
        }
    };
    const handleConfirmSelection = () => {
        if (selectedFiles.length > 0) {
            onFileSelect?.(selectedFiles);
            onClose();
        }
    };
    const formatFileSize = (bytes) => {
        if (bytes === 0)
            return "0 Bytes";
        const k = 1024;
        const sizes = ["Bytes", "KB", "MB", "GB"];
        const i = Math.floor(Math.log(bytes) / Math.log(k));
        return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
    };
    if (!isOpen)
        return null;
    return (jsxRuntime.jsx("div", { className: `fixed inset-0 z-50 flex items-center justify-center bg-black/20 p-4 ${className}`, children: jsxRuntime.jsxs("div", { className: "bg-white rounded-xl shadow-2xl w-full max-w-6xl h-full max-h-[90vh] flex flex-col overflow-hidden", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between p-6 border-b border-gray-200", children: [jsxRuntime.jsx("h2", { className: "text-xl font-semibold text-gray-900", children: title }), jsxRuntime.jsx("button", { onClick: onClose, className: "p-2 hover:bg-gray-100 rounded-lg transition-colors", children: jsxRuntime.jsx(lucideReact.X, { className: "w-5 h-5 text-gray-500" }) })] }), jsxRuntime.jsxs("div", { className: "flex flex-1 overflow-hidden", children: [jsxRuntime.jsxs("div", { className: "w-64 bg-gray-50 border-r border-gray-200 flex flex-col", children: [jsxRuntime.jsxs("div", { className: "p-4", children: [jsxRuntime.jsx("h3", { className: "text-sm font-medium text-gray-900 mb-3", children: "Upload from" }), jsxRuntime.jsx("nav", { className: "space-y-1", children: UPLOAD_SOURCES$1.map((source) => {
                                                const Icon = source.icon;
                                                const isActive = activeSource === source.id;
                                                const isDisabled = !["device", "camera", "url"].includes(source.id);
                                                return (jsxRuntime.jsxs("button", { onClick: () => !isDisabled &&
                                                        setActiveSource(source.id), disabled: isDisabled, className: `w-full flex items-center px-3 py-2 text-sm rounded-lg transition-colors ${isActive
                                                        ? "bg-blue-100 text-blue-700 border border-blue-200"
                                                        : isDisabled
                                                            ? "text-gray-400 cursor-not-allowed"
                                                            : "text-gray-700 hover:bg-gray-100"}`, children: [jsxRuntime.jsx(Icon, { className: "w-4 h-4 mr-3" }), jsxRuntime.jsxs("div", { className: "text-left", children: [jsxRuntime.jsx("div", { className: "font-medium", children: source.name }), isDisabled && (jsxRuntime.jsx("div", { className: "text-xs text-gray-400", children: "Coming soon" }))] })] }, source.id));
                                            }) })] }), showLibrary && (jsxRuntime.jsxs("div", { className: "flex-1 border-t border-gray-200 p-4", children: [jsxRuntime.jsxs("h3", { className: "text-sm font-medium text-gray-900 mb-3", children: ["File Library (", selectedFiles.length, " selected)"] }), selectedFiles.length > 0 && (jsxRuntime.jsx("button", { onClick: handleConfirmSelection, className: "w-full mb-3 px-3 py-2 bg-blue-600 text-white text-sm font-medium rounded-lg hover:bg-blue-700 transition-colors", children: "Use Selected Files" }))] }))] }), jsxRuntime.jsx("div", { className: "flex-1 flex flex-col overflow-hidden", children: jsxRuntime.jsxs("div", { className: "flex-1 p-6 overflow-auto", children: [activeSource === "device" && (jsxRuntime.jsx(DeviceUploadContent, { onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, isDragActive: isDragActive, fileInputRef: fileInputRef, onFileSelect: handleFileSelect, accept: accept, multiple: multiple, uploadingFiles: uploadingFiles, formatFileSize: formatFileSize })), activeSource === "camera" && (jsxRuntime.jsx(CameraUploadContent, { cameraInputRef: cameraInputRef, onFileSelect: handleFileSelect })), activeSource === "url" && (jsxRuntime.jsx(UrlUploadContent, { urlInput: urlInput, setUrlInput: setUrlInput, onUpload: handleUrlUpload })), showLibrary && (jsxRuntime.jsx(FileLibraryContent, { files: libraryFiles, selectedFiles: selectedFiles, onFileSelect: handleLibraryFileSelect, isLoading: isLoading, formatFileSize: formatFileSize }))] }) })] })] }) }));
};
// Device Upload Content Component
const DeviceUploadContent = ({ onDragEnter, onDragLeave, onDragOver, onDrop, isDragActive, fileInputRef, onFileSelect, accept, multiple, uploadingFiles, formatFileSize, }) => (jsxRuntime.jsxs("div", { className: "space-y-6", children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", accept: accept, multiple: multiple, onChange: onFileSelect, className: "hidden" }), jsxRuntime.jsx("div", { onDragEnter: onDragEnter, onDragLeave: onDragLeave, onDragOver: onDragOver, onDrop: onDrop, onClick: () => fileInputRef.current?.click(), className: `border-2 border-dashed rounded-xl p-12 text-center cursor-pointer transition-all duration-200 ${isDragActive
                ? "border-blue-500 bg-blue-50"
                : "border-gray-300 hover:border-gray-400 bg-gray-50 hover:bg-gray-100"}`, children: jsxRuntime.jsxs("div", { className: "space-y-4", children: [jsxRuntime.jsx("div", { className: `text-6xl ${isDragActive ? "text-blue-500" : "text-gray-400"}`, children: isDragActive ? "📂" : "📁" }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("h3", { className: "text-xl font-semibold text-gray-900 mb-2", children: isDragActive ? "Drop files here" : "Choose files to upload" }), jsxRuntime.jsx("p", { className: "text-gray-600", children: isDragActive
                                    ? "Release to upload your files"
                                    : "Drag and drop files here, or click to browse" }), jsxRuntime.jsx("p", { className: "text-sm text-gray-500 mt-2", children: "Supports: Images, Documents, Videos, and more" })] })] }) }), uploadingFiles.length > 0 && (jsxRuntime.jsxs("div", { className: "space-y-4", children: [jsxRuntime.jsx("h4", { className: "font-medium text-gray-900", children: "Uploading Files" }), jsxRuntime.jsx("div", { className: "space-y-3", children: uploadingFiles.map((file) => (jsxRuntime.jsx("div", { className: "bg-white border border-gray-200 rounded-lg p-4", children: jsxRuntime.jsxs("div", { className: "flex items-center space-x-4", children: [file.preview && (jsxRuntime.jsx("img", { src: file.preview, alt: "Preview", className: "w-12 h-12 object-cover rounded-lg" })), jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-900 truncate", children: file.file.name }), jsxRuntime.jsx("p", { className: "text-xs text-gray-500", children: formatFileSize(file.file.size) }), file.status === "uploading" && (jsxRuntime.jsxs("div", { className: "mt-2", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-xs text-gray-600 mb-1", children: [jsxRuntime.jsx("span", { children: "Uploading..." }), jsxRuntime.jsxs("span", { children: [file.progress, "%"] })] }), jsxRuntime.jsx("div", { className: "w-full bg-gray-200 rounded-full h-1.5", children: jsxRuntime.jsx("div", { className: "bg-blue-600 h-1.5 rounded-full transition-all duration-300", style: { width: `${file.progress}%` } }) })] })), file.status === "completed" && (jsxRuntime.jsx("p", { className: "text-xs text-green-600 mt-1", children: "\u2713 Upload complete" })), file.status === "error" && (jsxRuntime.jsxs("p", { className: "text-xs text-red-600 mt-1", children: ["\u2717 ", file.error] }))] })] }) }, file.id))) })] }))] }));
// Camera Upload Content Component
const CameraUploadContent = ({ cameraInputRef, onFileSelect }) => (jsxRuntime.jsxs("div", { className: "text-center space-y-6", children: [jsxRuntime.jsx("input", { ref: cameraInputRef, type: "file", accept: "image/*,video/*", capture: "environment", onChange: onFileSelect, className: "hidden" }), jsxRuntime.jsxs("div", { className: "space-y-4", children: [jsxRuntime.jsx(lucideReact.Camera, { className: "w-16 h-16 text-gray-400 mx-auto" }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("h3", { className: "text-xl font-semibold text-gray-900 mb-2", children: "Take Photo or Video" }), jsxRuntime.jsx("p", { className: "text-gray-600 mb-6", children: "Use your device's camera to capture photos or videos" }), jsxRuntime.jsx("button", { onClick: () => cameraInputRef.current?.click(), className: "px-6 py-3 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 transition-colors", children: "Open Camera" })] })] })] }));
// URL Upload Content Component
const UrlUploadContent = ({ urlInput, setUrlInput, onUpload }) => (jsxRuntime.jsxs("div", { className: "space-y-6", children: [jsxRuntime.jsxs("div", { className: "text-center space-y-4", children: [jsxRuntime.jsx(lucideReact.Link, { className: "w-16 h-16 text-gray-400 mx-auto" }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("h3", { className: "text-xl font-semibold text-gray-900 mb-2", children: "Import from URL" }), jsxRuntime.jsx("p", { className: "text-gray-600", children: "Enter a URL to import a file from the web" })] })] }), jsxRuntime.jsxs("div", { className: "max-w-md mx-auto space-y-4", children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: "File URL" }), jsxRuntime.jsx("input", { type: "url", value: urlInput, onChange: (e) => setUrlInput(e.target.value), placeholder: "https://example.com/file.pdf", className: "w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" })] }), jsxRuntime.jsx("button", { onClick: onUpload, disabled: !urlInput.trim(), className: "w-full px-4 py-2 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors", children: "Import File" })] })] }));
// File Library Content Component
const FileLibraryContent = ({ files, selectedFiles, onFileSelect, isLoading, formatFileSize }) => (jsxRuntime.jsxs("div", { className: "space-y-4", children: [jsxRuntime.jsx("h4", { className: "font-medium text-gray-900", children: "Your Files" }), isLoading ? (jsxRuntime.jsxs("div", { className: "text-center py-8", children: [jsxRuntime.jsx("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto" }), jsxRuntime.jsx("p", { className: "text-gray-600 mt-2", children: "Loading files..." })] })) : files.length === 0 ? (jsxRuntime.jsxs("div", { className: "text-center py-8", children: [jsxRuntime.jsx(lucideReact.Folder, { className: "w-12 h-12 text-gray-400 mx-auto mb-2" }), jsxRuntime.jsx("p", { className: "text-gray-600", children: "No files in your library yet" })] })) : (jsxRuntime.jsx("div", { className: "grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4", children: files.map((file) => {
                const isSelected = selectedFiles.some((f) => f.fileId === file.fileId);
                return (jsxRuntime.jsxs("div", { onClick: () => onFileSelect(file), className: `relative cursor-pointer rounded-lg border-2 transition-all ${isSelected
                        ? "border-blue-500 bg-blue-50"
                        : "border-gray-200 hover:border-gray-300"}`, children: [jsxRuntime.jsx("div", { className: "aspect-square bg-gray-100 rounded-t-lg flex items-center justify-center overflow-hidden", children: file.thumbnailUrl ? (jsxRuntime.jsx("img", { src: file.thumbnailUrl, alt: file.originalFilename, className: "w-full h-full object-cover" })) : (jsxRuntime.jsx("div", { className: "text-2xl text-gray-400", children: "\uD83D\uDCC4" })) }), jsxRuntime.jsxs("div", { className: "p-3", children: [jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-900 truncate", children: file.originalFilename }), jsxRuntime.jsx("p", { className: "text-xs text-gray-500", children: formatFileSize(file.fileSize) })] }), isSelected && (jsxRuntime.jsx("div", { className: "absolute top-2 right-2 w-6 h-6 bg-blue-600 text-white rounded-full flex items-center justify-center", children: jsxRuntime.jsx("span", { className: "text-xs", children: "\u2713" }) }))] }, file.fileId));
            }) }))] }));

const FileUploadTrigger = ({ config, options, onFileSelect, onSuccess, onError, children = 'Upload Files', className = '', style, multiple = true, accept = '*/*', maxFileSize, title = 'Upload Files', showLibrary = true, variant = 'primary', size = 'medium', disabled = false }) => {
    const [isWidgetOpen, setIsWidgetOpen] = React.useState(false);
    const getButtonStyles = () => {
        const baseStyles = {
            border: 'none',
            borderRadius: '8px',
            cursor: disabled ? 'not-allowed' : 'pointer',
            fontWeight: '500',
            transition: 'all 0.2s ease',
            display: 'inline-flex',
            alignItems: 'center',
            justifyContent: 'center',
            gap: '8px',
            opacity: disabled ? 0.6 : 1,
            ...style
        };
        // Size variants
        const sizeStyles = {
            small: { padding: '8px 16px', fontSize: '12px' },
            medium: { padding: '12px 20px', fontSize: '14px' },
            large: { padding: '16px 24px', fontSize: '16px' }
        };
        // Color variants
        const variantStyles = {
            primary: {
                backgroundColor: '#3b82f6',
                color: 'white',
                boxShadow: '0 2px 4px rgba(59, 130, 246, 0.2)'
            },
            secondary: {
                backgroundColor: '#6b7280',
                color: 'white',
                boxShadow: '0 2px 4px rgba(107, 114, 128, 0.2)'
            },
            outline: {
                backgroundColor: 'transparent',
                color: '#3b82f6',
                border: '1px solid #3b82f6'
            }
        };
        return {
            ...baseStyles,
            ...sizeStyles[size],
            ...variantStyles[variant]
        };
    };
    const handleClick = () => {
        if (!disabled) {
            setIsWidgetOpen(true);
        }
    };
    const handleFileSelect = (files) => {
        onFileSelect?.(files);
        setIsWidgetOpen(false);
    };
    const handleSuccess = (results) => {
        onSuccess?.(results);
    };
    const handleError = (error) => {
        onError?.(error);
    };
    return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("button", { className: `file-upload-trigger ${className}`, style: getButtonStyles(), onClick: handleClick, disabled: disabled, type: "button", children: [jsxRuntime.jsx(lucideReact.Upload, { className: "w-4 h-4" }), children] }), jsxRuntime.jsx(FileUploadWidget, { config: config, options: options, isOpen: isWidgetOpen, onClose: () => setIsWidgetOpen(false), onFileSelect: handleFileSelect, onSuccess: handleSuccess, onError: handleError, multiple: multiple, accept: accept, maxFileSize: maxFileSize, title: title, showLibrary: showLibrary })] }));
};

// packages/core/primitive/src/primitive.tsx
function composeEventHandlers(originalEventHandler, ourEventHandler, { checkForDefaultPrevented = true } = {}) {
  return function handleEvent(event) {
    originalEventHandler?.(event);
    if (checkForDefaultPrevented === false || !event.defaultPrevented) {
      return ourEventHandler?.(event);
    }
  };
}

// packages/react/compose-refs/src/compose-refs.tsx
function setRef(ref, value) {
  if (typeof ref === "function") {
    return ref(value);
  } else if (ref !== null && ref !== void 0) {
    ref.current = value;
  }
}
function composeRefs(...refs) {
  return (node) => {
    let hasCleanup = false;
    const cleanups = refs.map((ref) => {
      const cleanup = setRef(ref, node);
      if (!hasCleanup && typeof cleanup == "function") {
        hasCleanup = true;
      }
      return cleanup;
    });
    if (hasCleanup) {
      return () => {
        for (let i = 0; i < cleanups.length; i++) {
          const cleanup = cleanups[i];
          if (typeof cleanup == "function") {
            cleanup();
          } else {
            setRef(refs[i], null);
          }
        }
      };
    }
  };
}
function useComposedRefs(...refs) {
  return React__namespace.useCallback(composeRefs(...refs), refs);
}

// packages/react/context/src/create-context.tsx
function createContext2(rootComponentName, defaultContext) {
  const Context = React__namespace.createContext(defaultContext);
  const Provider = (props) => {
    const { children, ...context } = props;
    const value = React__namespace.useMemo(() => context, Object.values(context));
    return /* @__PURE__ */ jsxRuntime.jsx(Context.Provider, { value, children });
  };
  Provider.displayName = rootComponentName + "Provider";
  function useContext2(consumerName) {
    const context = React__namespace.useContext(Context);
    if (context) return context;
    if (defaultContext !== void 0) return defaultContext;
    throw new Error(`\`${consumerName}\` must be used within \`${rootComponentName}\``);
  }
  return [Provider, useContext2];
}
function createContextScope(scopeName, createContextScopeDeps = []) {
  let defaultContexts = [];
  function createContext3(rootComponentName, defaultContext) {
    const BaseContext = React__namespace.createContext(defaultContext);
    const index = defaultContexts.length;
    defaultContexts = [...defaultContexts, defaultContext];
    const Provider = (props) => {
      const { scope, children, ...context } = props;
      const Context = scope?.[scopeName]?.[index] || BaseContext;
      const value = React__namespace.useMemo(() => context, Object.values(context));
      return /* @__PURE__ */ jsxRuntime.jsx(Context.Provider, { value, children });
    };
    Provider.displayName = rootComponentName + "Provider";
    function useContext2(consumerName, scope) {
      const Context = scope?.[scopeName]?.[index] || BaseContext;
      const context = React__namespace.useContext(Context);
      if (context) return context;
      if (defaultContext !== void 0) return defaultContext;
      throw new Error(`\`${consumerName}\` must be used within \`${rootComponentName}\``);
    }
    return [Provider, useContext2];
  }
  const createScope = () => {
    const scopeContexts = defaultContexts.map((defaultContext) => {
      return React__namespace.createContext(defaultContext);
    });
    return function useScope(scope) {
      const contexts = scope?.[scopeName] || scopeContexts;
      return React__namespace.useMemo(
        () => ({ [`__scope${scopeName}`]: { ...scope, [scopeName]: contexts } }),
        [scope, contexts]
      );
    };
  };
  createScope.scopeName = scopeName;
  return [createContext3, composeContextScopes(createScope, ...createContextScopeDeps)];
}
function composeContextScopes(...scopes) {
  const baseScope = scopes[0];
  if (scopes.length === 1) return baseScope;
  const createScope = () => {
    const scopeHooks = scopes.map((createScope2) => ({
      useScope: createScope2(),
      scopeName: createScope2.scopeName
    }));
    return function useComposedScopes(overrideScopes) {
      const nextScopes = scopeHooks.reduce((nextScopes2, { useScope, scopeName }) => {
        const scopeProps = useScope(overrideScopes);
        const currentScope = scopeProps[`__scope${scopeName}`];
        return { ...nextScopes2, ...currentScope };
      }, {});
      return React__namespace.useMemo(() => ({ [`__scope${baseScope.scopeName}`]: nextScopes }), [nextScopes]);
    };
  };
  createScope.scopeName = baseScope.scopeName;
  return createScope;
}

// packages/react/use-layout-effect/src/use-layout-effect.tsx
var useLayoutEffect2 = globalThis?.document ? React__namespace.useLayoutEffect : () => {
};

// packages/react/id/src/id.tsx
var useReactId = React__namespace[" useId ".trim().toString()] || (() => void 0);
var count$1 = 0;
function useId(deterministicId) {
  const [id, setId] = React__namespace.useState(useReactId());
  useLayoutEffect2(() => {
    setId((reactId) => reactId ?? String(count$1++));
  }, [deterministicId]);
  return deterministicId || (id ? `radix-${id}` : "");
}

// src/use-controllable-state.tsx
var useInsertionEffect = React__namespace[" useInsertionEffect ".trim().toString()] || useLayoutEffect2;
function useControllableState({
  prop,
  defaultProp,
  onChange = () => {
  },
  caller
}) {
  const [uncontrolledProp, setUncontrolledProp, onChangeRef] = useUncontrolledState({
    defaultProp,
    onChange
  });
  const isControlled = prop !== void 0;
  const value = isControlled ? prop : uncontrolledProp;
  {
    const isControlledRef = React__namespace.useRef(prop !== void 0);
    React__namespace.useEffect(() => {
      const wasControlled = isControlledRef.current;
      if (wasControlled !== isControlled) {
        const from = wasControlled ? "controlled" : "uncontrolled";
        const to = isControlled ? "controlled" : "uncontrolled";
        console.warn(
          `${caller} is changing from ${from} to ${to}. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.`
        );
      }
      isControlledRef.current = isControlled;
    }, [isControlled, caller]);
  }
  const setValue = React__namespace.useCallback(
    (nextValue) => {
      if (isControlled) {
        const value2 = isFunction(nextValue) ? nextValue(prop) : nextValue;
        if (value2 !== prop) {
          onChangeRef.current?.(value2);
        }
      } else {
        setUncontrolledProp(nextValue);
      }
    },
    [isControlled, prop, setUncontrolledProp, onChangeRef]
  );
  return [value, setValue];
}
function useUncontrolledState({
  defaultProp,
  onChange
}) {
  const [value, setValue] = React__namespace.useState(defaultProp);
  const prevValueRef = React__namespace.useRef(value);
  const onChangeRef = React__namespace.useRef(onChange);
  useInsertionEffect(() => {
    onChangeRef.current = onChange;
  }, [onChange]);
  React__namespace.useEffect(() => {
    if (prevValueRef.current !== value) {
      onChangeRef.current?.(value);
      prevValueRef.current = value;
    }
  }, [value, prevValueRef]);
  return [value, setValue, onChangeRef];
}
function isFunction(value) {
  return typeof value === "function";
}

// src/slot.tsx
// @__NO_SIDE_EFFECTS__
function createSlot(ownerName) {
  const SlotClone = /* @__PURE__ */ createSlotClone(ownerName);
  const Slot2 = React__namespace.forwardRef((props, forwardedRef) => {
    const { children, ...slotProps } = props;
    const childrenArray = React__namespace.Children.toArray(children);
    const slottable = childrenArray.find(isSlottable);
    if (slottable) {
      const newElement = slottable.props.children;
      const newChildren = childrenArray.map((child) => {
        if (child === slottable) {
          if (React__namespace.Children.count(newElement) > 1) return React__namespace.Children.only(null);
          return React__namespace.isValidElement(newElement) ? newElement.props.children : null;
        } else {
          return child;
        }
      });
      return /* @__PURE__ */ jsxRuntime.jsx(SlotClone, { ...slotProps, ref: forwardedRef, children: React__namespace.isValidElement(newElement) ? React__namespace.cloneElement(newElement, void 0, newChildren) : null });
    }
    return /* @__PURE__ */ jsxRuntime.jsx(SlotClone, { ...slotProps, ref: forwardedRef, children });
  });
  Slot2.displayName = `${ownerName}.Slot`;
  return Slot2;
}
var Slot$1 = /* @__PURE__ */ createSlot("Slot");
// @__NO_SIDE_EFFECTS__
function createSlotClone(ownerName) {
  const SlotClone = React__namespace.forwardRef((props, forwardedRef) => {
    const { children, ...slotProps } = props;
    if (React__namespace.isValidElement(children)) {
      const childrenRef = getElementRef$1(children);
      const props2 = mergeProps(slotProps, children.props);
      if (children.type !== React__namespace.Fragment) {
        props2.ref = forwardedRef ? composeRefs(forwardedRef, childrenRef) : childrenRef;
      }
      return React__namespace.cloneElement(children, props2);
    }
    return React__namespace.Children.count(children) > 1 ? React__namespace.Children.only(null) : null;
  });
  SlotClone.displayName = `${ownerName}.SlotClone`;
  return SlotClone;
}
var SLOTTABLE_IDENTIFIER = Symbol("radix.slottable");
function isSlottable(child) {
  return React__namespace.isValidElement(child) && typeof child.type === "function" && "__radixId" in child.type && child.type.__radixId === SLOTTABLE_IDENTIFIER;
}
function mergeProps(slotProps, childProps) {
  const overrideProps = { ...childProps };
  for (const propName in childProps) {
    const slotPropValue = slotProps[propName];
    const childPropValue = childProps[propName];
    const isHandler = /^on[A-Z]/.test(propName);
    if (isHandler) {
      if (slotPropValue && childPropValue) {
        overrideProps[propName] = (...args) => {
          const result = childPropValue(...args);
          slotPropValue(...args);
          return result;
        };
      } else if (slotPropValue) {
        overrideProps[propName] = slotPropValue;
      }
    } else if (propName === "style") {
      overrideProps[propName] = { ...slotPropValue, ...childPropValue };
    } else if (propName === "className") {
      overrideProps[propName] = [slotPropValue, childPropValue].filter(Boolean).join(" ");
    }
  }
  return { ...slotProps, ...overrideProps };
}
function getElementRef$1(element) {
  let getter = Object.getOwnPropertyDescriptor(element.props, "ref")?.get;
  let mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
  if (mayWarn) {
    return element.ref;
  }
  getter = Object.getOwnPropertyDescriptor(element, "ref")?.get;
  mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
  if (mayWarn) {
    return element.props.ref;
  }
  return element.props.ref || element.ref;
}

// src/primitive.tsx
var NODES = [
  "a",
  "button",
  "div",
  "form",
  "h2",
  "h3",
  "img",
  "input",
  "label",
  "li",
  "nav",
  "ol",
  "p",
  "select",
  "span",
  "svg",
  "ul"
];
var Primitive = NODES.reduce((primitive, node) => {
  const Slot = createSlot(`Primitive.${node}`);
  const Node = React__namespace.forwardRef((props, forwardedRef) => {
    const { asChild, ...primitiveProps } = props;
    const Comp = asChild ? Slot : node;
    if (typeof window !== "undefined") {
      window[Symbol.for("radix-ui")] = true;
    }
    return /* @__PURE__ */ jsxRuntime.jsx(Comp, { ...primitiveProps, ref: forwardedRef });
  });
  Node.displayName = `Primitive.${node}`;
  return { ...primitive, [node]: Node };
}, {});
function dispatchDiscreteCustomEvent(target, event) {
  if (target) ReactDOM__namespace.flushSync(() => target.dispatchEvent(event));
}

// packages/react/use-callback-ref/src/use-callback-ref.tsx
function useCallbackRef$1(callback) {
  const callbackRef = React__namespace.useRef(callback);
  React__namespace.useEffect(() => {
    callbackRef.current = callback;
  });
  return React__namespace.useMemo(() => (...args) => callbackRef.current?.(...args), []);
}

// packages/react/use-escape-keydown/src/use-escape-keydown.tsx
function useEscapeKeydown(onEscapeKeyDownProp, ownerDocument = globalThis?.document) {
  const onEscapeKeyDown = useCallbackRef$1(onEscapeKeyDownProp);
  React__namespace.useEffect(() => {
    const handleKeyDown = (event) => {
      if (event.key === "Escape") {
        onEscapeKeyDown(event);
      }
    };
    ownerDocument.addEventListener("keydown", handleKeyDown, { capture: true });
    return () => ownerDocument.removeEventListener("keydown", handleKeyDown, { capture: true });
  }, [onEscapeKeyDown, ownerDocument]);
}

var DISMISSABLE_LAYER_NAME = "DismissableLayer";
var CONTEXT_UPDATE = "dismissableLayer.update";
var POINTER_DOWN_OUTSIDE = "dismissableLayer.pointerDownOutside";
var FOCUS_OUTSIDE = "dismissableLayer.focusOutside";
var originalBodyPointerEvents;
var DismissableLayerContext = React__namespace.createContext({
  layers: /* @__PURE__ */ new Set(),
  layersWithOutsidePointerEventsDisabled: /* @__PURE__ */ new Set(),
  branches: /* @__PURE__ */ new Set()
});
var DismissableLayer = React__namespace.forwardRef(
  (props, forwardedRef) => {
    const {
      disableOutsidePointerEvents = false,
      onEscapeKeyDown,
      onPointerDownOutside,
      onFocusOutside,
      onInteractOutside,
      onDismiss,
      ...layerProps
    } = props;
    const context = React__namespace.useContext(DismissableLayerContext);
    const [node, setNode] = React__namespace.useState(null);
    const ownerDocument = node?.ownerDocument ?? globalThis?.document;
    const [, force] = React__namespace.useState({});
    const composedRefs = useComposedRefs(forwardedRef, (node2) => setNode(node2));
    const layers = Array.from(context.layers);
    const [highestLayerWithOutsidePointerEventsDisabled] = [...context.layersWithOutsidePointerEventsDisabled].slice(-1);
    const highestLayerWithOutsidePointerEventsDisabledIndex = layers.indexOf(highestLayerWithOutsidePointerEventsDisabled);
    const index = node ? layers.indexOf(node) : -1;
    const isBodyPointerEventsDisabled = context.layersWithOutsidePointerEventsDisabled.size > 0;
    const isPointerEventsEnabled = index >= highestLayerWithOutsidePointerEventsDisabledIndex;
    const pointerDownOutside = usePointerDownOutside((event) => {
      const target = event.target;
      const isPointerDownOnBranch = [...context.branches].some((branch) => branch.contains(target));
      if (!isPointerEventsEnabled || isPointerDownOnBranch) return;
      onPointerDownOutside?.(event);
      onInteractOutside?.(event);
      if (!event.defaultPrevented) onDismiss?.();
    }, ownerDocument);
    const focusOutside = useFocusOutside((event) => {
      const target = event.target;
      const isFocusInBranch = [...context.branches].some((branch) => branch.contains(target));
      if (isFocusInBranch) return;
      onFocusOutside?.(event);
      onInteractOutside?.(event);
      if (!event.defaultPrevented) onDismiss?.();
    }, ownerDocument);
    useEscapeKeydown((event) => {
      const isHighestLayer = index === context.layers.size - 1;
      if (!isHighestLayer) return;
      onEscapeKeyDown?.(event);
      if (!event.defaultPrevented && onDismiss) {
        event.preventDefault();
        onDismiss();
      }
    }, ownerDocument);
    React__namespace.useEffect(() => {
      if (!node) return;
      if (disableOutsidePointerEvents) {
        if (context.layersWithOutsidePointerEventsDisabled.size === 0) {
          originalBodyPointerEvents = ownerDocument.body.style.pointerEvents;
          ownerDocument.body.style.pointerEvents = "none";
        }
        context.layersWithOutsidePointerEventsDisabled.add(node);
      }
      context.layers.add(node);
      dispatchUpdate();
      return () => {
        if (disableOutsidePointerEvents && context.layersWithOutsidePointerEventsDisabled.size === 1) {
          ownerDocument.body.style.pointerEvents = originalBodyPointerEvents;
        }
      };
    }, [node, ownerDocument, disableOutsidePointerEvents, context]);
    React__namespace.useEffect(() => {
      return () => {
        if (!node) return;
        context.layers.delete(node);
        context.layersWithOutsidePointerEventsDisabled.delete(node);
        dispatchUpdate();
      };
    }, [node, context]);
    React__namespace.useEffect(() => {
      const handleUpdate = () => force({});
      document.addEventListener(CONTEXT_UPDATE, handleUpdate);
      return () => document.removeEventListener(CONTEXT_UPDATE, handleUpdate);
    }, []);
    return /* @__PURE__ */ jsxRuntime.jsx(
      Primitive.div,
      {
        ...layerProps,
        ref: composedRefs,
        style: {
          pointerEvents: isBodyPointerEventsDisabled ? isPointerEventsEnabled ? "auto" : "none" : void 0,
          ...props.style
        },
        onFocusCapture: composeEventHandlers(props.onFocusCapture, focusOutside.onFocusCapture),
        onBlurCapture: composeEventHandlers(props.onBlurCapture, focusOutside.onBlurCapture),
        onPointerDownCapture: composeEventHandlers(
          props.onPointerDownCapture,
          pointerDownOutside.onPointerDownCapture
        )
      }
    );
  }
);
DismissableLayer.displayName = DISMISSABLE_LAYER_NAME;
var BRANCH_NAME = "DismissableLayerBranch";
var DismissableLayerBranch = React__namespace.forwardRef((props, forwardedRef) => {
  const context = React__namespace.useContext(DismissableLayerContext);
  const ref = React__namespace.useRef(null);
  const composedRefs = useComposedRefs(forwardedRef, ref);
  React__namespace.useEffect(() => {
    const node = ref.current;
    if (node) {
      context.branches.add(node);
      return () => {
        context.branches.delete(node);
      };
    }
  }, [context.branches]);
  return /* @__PURE__ */ jsxRuntime.jsx(Primitive.div, { ...props, ref: composedRefs });
});
DismissableLayerBranch.displayName = BRANCH_NAME;
function usePointerDownOutside(onPointerDownOutside, ownerDocument = globalThis?.document) {
  const handlePointerDownOutside = useCallbackRef$1(onPointerDownOutside);
  const isPointerInsideReactTreeRef = React__namespace.useRef(false);
  const handleClickRef = React__namespace.useRef(() => {
  });
  React__namespace.useEffect(() => {
    const handlePointerDown = (event) => {
      if (event.target && !isPointerInsideReactTreeRef.current) {
        let handleAndDispatchPointerDownOutsideEvent2 = function() {
          handleAndDispatchCustomEvent(
            POINTER_DOWN_OUTSIDE,
            handlePointerDownOutside,
            eventDetail,
            { discrete: true }
          );
        };
        const eventDetail = { originalEvent: event };
        if (event.pointerType === "touch") {
          ownerDocument.removeEventListener("click", handleClickRef.current);
          handleClickRef.current = handleAndDispatchPointerDownOutsideEvent2;
          ownerDocument.addEventListener("click", handleClickRef.current, { once: true });
        } else {
          handleAndDispatchPointerDownOutsideEvent2();
        }
      } else {
        ownerDocument.removeEventListener("click", handleClickRef.current);
      }
      isPointerInsideReactTreeRef.current = false;
    };
    const timerId = window.setTimeout(() => {
      ownerDocument.addEventListener("pointerdown", handlePointerDown);
    }, 0);
    return () => {
      window.clearTimeout(timerId);
      ownerDocument.removeEventListener("pointerdown", handlePointerDown);
      ownerDocument.removeEventListener("click", handleClickRef.current);
    };
  }, [ownerDocument, handlePointerDownOutside]);
  return {
    // ensures we check React component tree (not just DOM tree)
    onPointerDownCapture: () => isPointerInsideReactTreeRef.current = true
  };
}
function useFocusOutside(onFocusOutside, ownerDocument = globalThis?.document) {
  const handleFocusOutside = useCallbackRef$1(onFocusOutside);
  const isFocusInsideReactTreeRef = React__namespace.useRef(false);
  React__namespace.useEffect(() => {
    const handleFocus = (event) => {
      if (event.target && !isFocusInsideReactTreeRef.current) {
        const eventDetail = { originalEvent: event };
        handleAndDispatchCustomEvent(FOCUS_OUTSIDE, handleFocusOutside, eventDetail, {
          discrete: false
        });
      }
    };
    ownerDocument.addEventListener("focusin", handleFocus);
    return () => ownerDocument.removeEventListener("focusin", handleFocus);
  }, [ownerDocument, handleFocusOutside]);
  return {
    onFocusCapture: () => isFocusInsideReactTreeRef.current = true,
    onBlurCapture: () => isFocusInsideReactTreeRef.current = false
  };
}
function dispatchUpdate() {
  const event = new CustomEvent(CONTEXT_UPDATE);
  document.dispatchEvent(event);
}
function handleAndDispatchCustomEvent(name, handler, detail, { discrete }) {
  const target = detail.originalEvent.target;
  const event = new CustomEvent(name, { bubbles: false, cancelable: true, detail });
  if (handler) target.addEventListener(name, handler, { once: true });
  if (discrete) {
    dispatchDiscreteCustomEvent(target, event);
  } else {
    target.dispatchEvent(event);
  }
}

var AUTOFOCUS_ON_MOUNT = "focusScope.autoFocusOnMount";
var AUTOFOCUS_ON_UNMOUNT = "focusScope.autoFocusOnUnmount";
var EVENT_OPTIONS = { bubbles: false, cancelable: true };
var FOCUS_SCOPE_NAME = "FocusScope";
var FocusScope = React__namespace.forwardRef((props, forwardedRef) => {
  const {
    loop = false,
    trapped = false,
    onMountAutoFocus: onMountAutoFocusProp,
    onUnmountAutoFocus: onUnmountAutoFocusProp,
    ...scopeProps
  } = props;
  const [container, setContainer] = React__namespace.useState(null);
  const onMountAutoFocus = useCallbackRef$1(onMountAutoFocusProp);
  const onUnmountAutoFocus = useCallbackRef$1(onUnmountAutoFocusProp);
  const lastFocusedElementRef = React__namespace.useRef(null);
  const composedRefs = useComposedRefs(forwardedRef, (node) => setContainer(node));
  const focusScope = React__namespace.useRef({
    paused: false,
    pause() {
      this.paused = true;
    },
    resume() {
      this.paused = false;
    }
  }).current;
  React__namespace.useEffect(() => {
    if (trapped) {
      let handleFocusIn2 = function(event) {
        if (focusScope.paused || !container) return;
        const target = event.target;
        if (container.contains(target)) {
          lastFocusedElementRef.current = target;
        } else {
          focus(lastFocusedElementRef.current, { select: true });
        }
      }, handleFocusOut2 = function(event) {
        if (focusScope.paused || !container) return;
        const relatedTarget = event.relatedTarget;
        if (relatedTarget === null) return;
        if (!container.contains(relatedTarget)) {
          focus(lastFocusedElementRef.current, { select: true });
        }
      }, handleMutations2 = function(mutations) {
        const focusedElement = document.activeElement;
        if (focusedElement !== document.body) return;
        for (const mutation of mutations) {
          if (mutation.removedNodes.length > 0) focus(container);
        }
      };
      document.addEventListener("focusin", handleFocusIn2);
      document.addEventListener("focusout", handleFocusOut2);
      const mutationObserver = new MutationObserver(handleMutations2);
      if (container) mutationObserver.observe(container, { childList: true, subtree: true });
      return () => {
        document.removeEventListener("focusin", handleFocusIn2);
        document.removeEventListener("focusout", handleFocusOut2);
        mutationObserver.disconnect();
      };
    }
  }, [trapped, container, focusScope.paused]);
  React__namespace.useEffect(() => {
    if (container) {
      focusScopesStack.add(focusScope);
      const previouslyFocusedElement = document.activeElement;
      const hasFocusedCandidate = container.contains(previouslyFocusedElement);
      if (!hasFocusedCandidate) {
        const mountEvent = new CustomEvent(AUTOFOCUS_ON_MOUNT, EVENT_OPTIONS);
        container.addEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);
        container.dispatchEvent(mountEvent);
        if (!mountEvent.defaultPrevented) {
          focusFirst(removeLinks(getTabbableCandidates(container)), { select: true });
          if (document.activeElement === previouslyFocusedElement) {
            focus(container);
          }
        }
      }
      return () => {
        container.removeEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);
        setTimeout(() => {
          const unmountEvent = new CustomEvent(AUTOFOCUS_ON_UNMOUNT, EVENT_OPTIONS);
          container.addEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);
          container.dispatchEvent(unmountEvent);
          if (!unmountEvent.defaultPrevented) {
            focus(previouslyFocusedElement ?? document.body, { select: true });
          }
          container.removeEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);
          focusScopesStack.remove(focusScope);
        }, 0);
      };
    }
  }, [container, onMountAutoFocus, onUnmountAutoFocus, focusScope]);
  const handleKeyDown = React__namespace.useCallback(
    (event) => {
      if (!loop && !trapped) return;
      if (focusScope.paused) return;
      const isTabKey = event.key === "Tab" && !event.altKey && !event.ctrlKey && !event.metaKey;
      const focusedElement = document.activeElement;
      if (isTabKey && focusedElement) {
        const container2 = event.currentTarget;
        const [first, last] = getTabbableEdges(container2);
        const hasTabbableElementsInside = first && last;
        if (!hasTabbableElementsInside) {
          if (focusedElement === container2) event.preventDefault();
        } else {
          if (!event.shiftKey && focusedElement === last) {
            event.preventDefault();
            if (loop) focus(first, { select: true });
          } else if (event.shiftKey && focusedElement === first) {
            event.preventDefault();
            if (loop) focus(last, { select: true });
          }
        }
      }
    },
    [loop, trapped, focusScope.paused]
  );
  return /* @__PURE__ */ jsxRuntime.jsx(Primitive.div, { tabIndex: -1, ...scopeProps, ref: composedRefs, onKeyDown: handleKeyDown });
});
FocusScope.displayName = FOCUS_SCOPE_NAME;
function focusFirst(candidates, { select = false } = {}) {
  const previouslyFocusedElement = document.activeElement;
  for (const candidate of candidates) {
    focus(candidate, { select });
    if (document.activeElement !== previouslyFocusedElement) return;
  }
}
function getTabbableEdges(container) {
  const candidates = getTabbableCandidates(container);
  const first = findVisible(candidates, container);
  const last = findVisible(candidates.reverse(), container);
  return [first, last];
}
function getTabbableCandidates(container) {
  const nodes = [];
  const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
    acceptNode: (node) => {
      const isHiddenInput = node.tagName === "INPUT" && node.type === "hidden";
      if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP;
      return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
    }
  });
  while (walker.nextNode()) nodes.push(walker.currentNode);
  return nodes;
}
function findVisible(elements, container) {
  for (const element of elements) {
    if (!isHidden(element, { upTo: container })) return element;
  }
}
function isHidden(node, { upTo }) {
  if (getComputedStyle(node).visibility === "hidden") return true;
  while (node) {
    if (upTo !== void 0 && node === upTo) return false;
    if (getComputedStyle(node).display === "none") return true;
    node = node.parentElement;
  }
  return false;
}
function isSelectableInput(element) {
  return element instanceof HTMLInputElement && "select" in element;
}
function focus(element, { select = false } = {}) {
  if (element && element.focus) {
    const previouslyFocusedElement = document.activeElement;
    element.focus({ preventScroll: true });
    if (element !== previouslyFocusedElement && isSelectableInput(element) && select)
      element.select();
  }
}
var focusScopesStack = createFocusScopesStack();
function createFocusScopesStack() {
  let stack = [];
  return {
    add(focusScope) {
      const activeFocusScope = stack[0];
      if (focusScope !== activeFocusScope) {
        activeFocusScope?.pause();
      }
      stack = arrayRemove(stack, focusScope);
      stack.unshift(focusScope);
    },
    remove(focusScope) {
      stack = arrayRemove(stack, focusScope);
      stack[0]?.resume();
    }
  };
}
function arrayRemove(array, item) {
  const updatedArray = [...array];
  const index = updatedArray.indexOf(item);
  if (index !== -1) {
    updatedArray.splice(index, 1);
  }
  return updatedArray;
}
function removeLinks(items) {
  return items.filter((item) => item.tagName !== "A");
}

var PORTAL_NAME$1 = "Portal";
var Portal$1 = React__namespace.forwardRef((props, forwardedRef) => {
  const { container: containerProp, ...portalProps } = props;
  const [mounted, setMounted] = React__namespace.useState(false);
  useLayoutEffect2(() => setMounted(true), []);
  const container = containerProp || mounted && globalThis?.document?.body;
  return container ? ReactDOM.createPortal(/* @__PURE__ */ jsxRuntime.jsx(Primitive.div, { ...portalProps, ref: forwardedRef }), container) : null;
});
Portal$1.displayName = PORTAL_NAME$1;

function useStateMachine(initialState, machine) {
  return React__namespace.useReducer((state, event) => {
    const nextState = machine[state][event];
    return nextState ?? state;
  }, initialState);
}

// src/presence.tsx
var Presence = (props) => {
  const { present, children } = props;
  const presence = usePresence(present);
  const child = typeof children === "function" ? children({ present: presence.isPresent }) : React__namespace.Children.only(children);
  const ref = useComposedRefs(presence.ref, getElementRef(child));
  const forceMount = typeof children === "function";
  return forceMount || presence.isPresent ? React__namespace.cloneElement(child, { ref }) : null;
};
Presence.displayName = "Presence";
function usePresence(present) {
  const [node, setNode] = React__namespace.useState();
  const stylesRef = React__namespace.useRef(null);
  const prevPresentRef = React__namespace.useRef(present);
  const prevAnimationNameRef = React__namespace.useRef("none");
  const initialState = present ? "mounted" : "unmounted";
  const [state, send] = useStateMachine(initialState, {
    mounted: {
      UNMOUNT: "unmounted",
      ANIMATION_OUT: "unmountSuspended"
    },
    unmountSuspended: {
      MOUNT: "mounted",
      ANIMATION_END: "unmounted"
    },
    unmounted: {
      MOUNT: "mounted"
    }
  });
  React__namespace.useEffect(() => {
    const currentAnimationName = getAnimationName(stylesRef.current);
    prevAnimationNameRef.current = state === "mounted" ? currentAnimationName : "none";
  }, [state]);
  useLayoutEffect2(() => {
    const styles = stylesRef.current;
    const wasPresent = prevPresentRef.current;
    const hasPresentChanged = wasPresent !== present;
    if (hasPresentChanged) {
      const prevAnimationName = prevAnimationNameRef.current;
      const currentAnimationName = getAnimationName(styles);
      if (present) {
        send("MOUNT");
      } else if (currentAnimationName === "none" || styles?.display === "none") {
        send("UNMOUNT");
      } else {
        const isAnimating = prevAnimationName !== currentAnimationName;
        if (wasPresent && isAnimating) {
          send("ANIMATION_OUT");
        } else {
          send("UNMOUNT");
        }
      }
      prevPresentRef.current = present;
    }
  }, [present, send]);
  useLayoutEffect2(() => {
    if (node) {
      let timeoutId;
      const ownerWindow = node.ownerDocument.defaultView ?? window;
      const handleAnimationEnd = (event) => {
        const currentAnimationName = getAnimationName(stylesRef.current);
        const isCurrentAnimation = currentAnimationName.includes(event.animationName);
        if (event.target === node && isCurrentAnimation) {
          send("ANIMATION_END");
          if (!prevPresentRef.current) {
            const currentFillMode = node.style.animationFillMode;
            node.style.animationFillMode = "forwards";
            timeoutId = ownerWindow.setTimeout(() => {
              if (node.style.animationFillMode === "forwards") {
                node.style.animationFillMode = currentFillMode;
              }
            });
          }
        }
      };
      const handleAnimationStart = (event) => {
        if (event.target === node) {
          prevAnimationNameRef.current = getAnimationName(stylesRef.current);
        }
      };
      node.addEventListener("animationstart", handleAnimationStart);
      node.addEventListener("animationcancel", handleAnimationEnd);
      node.addEventListener("animationend", handleAnimationEnd);
      return () => {
        ownerWindow.clearTimeout(timeoutId);
        node.removeEventListener("animationstart", handleAnimationStart);
        node.removeEventListener("animationcancel", handleAnimationEnd);
        node.removeEventListener("animationend", handleAnimationEnd);
      };
    } else {
      send("ANIMATION_END");
    }
  }, [node, send]);
  return {
    isPresent: ["mounted", "unmountSuspended"].includes(state),
    ref: React__namespace.useCallback((node2) => {
      stylesRef.current = node2 ? getComputedStyle(node2) : null;
      setNode(node2);
    }, [])
  };
}
function getAnimationName(styles) {
  return styles?.animationName || "none";
}
function getElementRef(element) {
  let getter = Object.getOwnPropertyDescriptor(element.props, "ref")?.get;
  let mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
  if (mayWarn) {
    return element.ref;
  }
  getter = Object.getOwnPropertyDescriptor(element, "ref")?.get;
  mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
  if (mayWarn) {
    return element.props.ref;
  }
  return element.props.ref || element.ref;
}

var count = 0;
function useFocusGuards() {
  React__namespace.useEffect(() => {
    const edgeGuards = document.querySelectorAll("[data-radix-focus-guard]");
    document.body.insertAdjacentElement("afterbegin", edgeGuards[0] ?? createFocusGuard());
    document.body.insertAdjacentElement("beforeend", edgeGuards[1] ?? createFocusGuard());
    count++;
    return () => {
      if (count === 1) {
        document.querySelectorAll("[data-radix-focus-guard]").forEach((node) => node.remove());
      }
      count--;
    };
  }, []);
}
function createFocusGuard() {
  const element = document.createElement("span");
  element.setAttribute("data-radix-focus-guard", "");
  element.tabIndex = 0;
  element.style.outline = "none";
  element.style.opacity = "0";
  element.style.position = "fixed";
  element.style.pointerEvents = "none";
  return element;
}

/******************************************************************************
Copyright (c) Microsoft Corporation.

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */


var __assign = function() {
    __assign = Object.assign || function __assign(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};

function __rest(s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
}

function __spreadArray(to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
}

typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
    var e = new Error(message);
    return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};

var zeroRightClassName = 'right-scroll-bar-position';
var fullWidthClassName = 'width-before-scroll-bar';
var noScrollbarsClassName = 'with-scroll-bars-hidden';
/**
 * Name of a CSS variable containing the amount of "hidden" scrollbar
 * ! might be undefined ! use will fallback!
 */
var removedBarSizeVariable = '--removed-body-scroll-bar-size';

/**
 * Assigns a value for a given ref, no matter of the ref format
 * @param {RefObject} ref - a callback function or ref object
 * @param value - a new value
 *
 * @see https://github.com/theKashey/use-callback-ref#assignref
 * @example
 * const refObject = useRef();
 * const refFn = (ref) => {....}
 *
 * assignRef(refObject, "refValue");
 * assignRef(refFn, "refValue");
 */
function assignRef(ref, value) {
    if (typeof ref === 'function') {
        ref(value);
    }
    else if (ref) {
        ref.current = value;
    }
    return ref;
}

/**
 * creates a MutableRef with ref change callback
 * @param initialValue - initial ref value
 * @param {Function} callback - a callback to run when value changes
 *
 * @example
 * const ref = useCallbackRef(0, (newValue, oldValue) => console.log(oldValue, '->', newValue);
 * ref.current = 1;
 * // prints 0 -> 1
 *
 * @see https://reactjs.org/docs/hooks-reference.html#useref
 * @see https://github.com/theKashey/use-callback-ref#usecallbackref---to-replace-reactuseref
 * @returns {MutableRefObject}
 */
function useCallbackRef(initialValue, callback) {
    var ref = React.useState(function () { return ({
        // value
        value: initialValue,
        // last callback
        callback: callback,
        // "memoized" public interface
        facade: {
            get current() {
                return ref.value;
            },
            set current(value) {
                var last = ref.value;
                if (last !== value) {
                    ref.value = value;
                    ref.callback(value, last);
                }
            },
        },
    }); })[0];
    // update callback
    ref.callback = callback;
    return ref.facade;
}

var useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React__namespace.useLayoutEffect : React__namespace.useEffect;
var currentValues = new WeakMap();
/**
 * Merges two or more refs together providing a single interface to set their value
 * @param {RefObject|Ref} refs
 * @returns {MutableRefObject} - a new ref, which translates all changes to {refs}
 *
 * @see {@link mergeRefs} a version without buit-in memoization
 * @see https://github.com/theKashey/use-callback-ref#usemergerefs
 * @example
 * const Component = React.forwardRef((props, ref) => {
 *   const ownRef = useRef();
 *   const domRef = useMergeRefs([ref, ownRef]); // 👈 merge together
 *   return <div ref={domRef}>...</div>
 * }
 */
function useMergeRefs(refs, defaultValue) {
    var callbackRef = useCallbackRef(null, function (newValue) {
        return refs.forEach(function (ref) { return assignRef(ref, newValue); });
    });
    // handle refs changes - added or removed
    useIsomorphicLayoutEffect(function () {
        var oldValue = currentValues.get(callbackRef);
        if (oldValue) {
            var prevRefs_1 = new Set(oldValue);
            var nextRefs_1 = new Set(refs);
            var current_1 = callbackRef.current;
            prevRefs_1.forEach(function (ref) {
                if (!nextRefs_1.has(ref)) {
                    assignRef(ref, null);
                }
            });
            nextRefs_1.forEach(function (ref) {
                if (!prevRefs_1.has(ref)) {
                    assignRef(ref, current_1);
                }
            });
        }
        currentValues.set(callbackRef, refs);
    }, [refs]);
    return callbackRef;
}

function ItoI(a) {
    return a;
}
function innerCreateMedium(defaults, middleware) {
    if (middleware === void 0) { middleware = ItoI; }
    var buffer = [];
    var assigned = false;
    var medium = {
        read: function () {
            if (assigned) {
                throw new Error('Sidecar: could not `read` from an `assigned` medium. `read` could be used only with `useMedium`.');
            }
            if (buffer.length) {
                return buffer[buffer.length - 1];
            }
            return defaults;
        },
        useMedium: function (data) {
            var item = middleware(data, assigned);
            buffer.push(item);
            return function () {
                buffer = buffer.filter(function (x) { return x !== item; });
            };
        },
        assignSyncMedium: function (cb) {
            assigned = true;
            while (buffer.length) {
                var cbs = buffer;
                buffer = [];
                cbs.forEach(cb);
            }
            buffer = {
                push: function (x) { return cb(x); },
                filter: function () { return buffer; },
            };
        },
        assignMedium: function (cb) {
            assigned = true;
            var pendingQueue = [];
            if (buffer.length) {
                var cbs = buffer;
                buffer = [];
                cbs.forEach(cb);
                pendingQueue = buffer;
            }
            var executeQueue = function () {
                var cbs = pendingQueue;
                pendingQueue = [];
                cbs.forEach(cb);
            };
            var cycle = function () { return Promise.resolve().then(executeQueue); };
            cycle();
            buffer = {
                push: function (x) {
                    pendingQueue.push(x);
                    cycle();
                },
                filter: function (filter) {
                    pendingQueue = pendingQueue.filter(filter);
                    return buffer;
                },
            };
        },
    };
    return medium;
}
// eslint-disable-next-line @typescript-eslint/ban-types
function createSidecarMedium(options) {
    if (options === void 0) { options = {}; }
    var medium = innerCreateMedium(null);
    medium.options = __assign({ async: true, ssr: false }, options);
    return medium;
}

var SideCar$1 = function (_a) {
    var sideCar = _a.sideCar, rest = __rest(_a, ["sideCar"]);
    if (!sideCar) {
        throw new Error('Sidecar: please provide `sideCar` property to import the right car');
    }
    var Target = sideCar.read();
    if (!Target) {
        throw new Error('Sidecar medium not found');
    }
    return React__namespace.createElement(Target, __assign({}, rest));
};
SideCar$1.isSideCarExport = true;
function exportSidecar(medium, exported) {
    medium.useMedium(exported);
    return SideCar$1;
}

var effectCar = createSidecarMedium();

var nothing = function () {
    return;
};
/**
 * Removes scrollbar from the page and contain the scroll within the Lock
 */
var RemoveScroll = React__namespace.forwardRef(function (props, parentRef) {
    var ref = React__namespace.useRef(null);
    var _a = React__namespace.useState({
        onScrollCapture: nothing,
        onWheelCapture: nothing,
        onTouchMoveCapture: nothing,
    }), callbacks = _a[0], setCallbacks = _a[1];
    var forwardProps = props.forwardProps, children = props.children, className = props.className, removeScrollBar = props.removeScrollBar, enabled = props.enabled, shards = props.shards, sideCar = props.sideCar, noRelative = props.noRelative, noIsolation = props.noIsolation, inert = props.inert, allowPinchZoom = props.allowPinchZoom, _b = props.as, Container = _b === void 0 ? 'div' : _b, gapMode = props.gapMode, rest = __rest(props, ["forwardProps", "children", "className", "removeScrollBar", "enabled", "shards", "sideCar", "noRelative", "noIsolation", "inert", "allowPinchZoom", "as", "gapMode"]);
    var SideCar = sideCar;
    var containerRef = useMergeRefs([ref, parentRef]);
    var containerProps = __assign(__assign({}, rest), callbacks);
    return (React__namespace.createElement(React__namespace.Fragment, null,
        enabled && (React__namespace.createElement(SideCar, { sideCar: effectCar, removeScrollBar: removeScrollBar, shards: shards, noRelative: noRelative, noIsolation: noIsolation, inert: inert, setCallbacks: setCallbacks, allowPinchZoom: !!allowPinchZoom, lockRef: ref, gapMode: gapMode })),
        forwardProps ? (React__namespace.cloneElement(React__namespace.Children.only(children), __assign(__assign({}, containerProps), { ref: containerRef }))) : (React__namespace.createElement(Container, __assign({}, containerProps, { className: className, ref: containerRef }), children))));
});
RemoveScroll.defaultProps = {
    enabled: true,
    removeScrollBar: true,
    inert: false,
};
RemoveScroll.classNames = {
    fullWidth: fullWidthClassName,
    zeroRight: zeroRightClassName,
};

var getNonce = function () {
    if (typeof __webpack_nonce__ !== 'undefined') {
        return __webpack_nonce__;
    }
    return undefined;
};

function makeStyleTag() {
    if (!document)
        return null;
    var tag = document.createElement('style');
    tag.type = 'text/css';
    var nonce = getNonce();
    if (nonce) {
        tag.setAttribute('nonce', nonce);
    }
    return tag;
}
function injectStyles(tag, css) {
    // @ts-ignore
    if (tag.styleSheet) {
        // @ts-ignore
        tag.styleSheet.cssText = css;
    }
    else {
        tag.appendChild(document.createTextNode(css));
    }
}
function insertStyleTag(tag) {
    var head = document.head || document.getElementsByTagName('head')[0];
    head.appendChild(tag);
}
var stylesheetSingleton = function () {
    var counter = 0;
    var stylesheet = null;
    return {
        add: function (style) {
            if (counter == 0) {
                if ((stylesheet = makeStyleTag())) {
                    injectStyles(stylesheet, style);
                    insertStyleTag(stylesheet);
                }
            }
            counter++;
        },
        remove: function () {
            counter--;
            if (!counter && stylesheet) {
                stylesheet.parentNode && stylesheet.parentNode.removeChild(stylesheet);
                stylesheet = null;
            }
        },
    };
};

/**
 * creates a hook to control style singleton
 * @see {@link styleSingleton} for a safer component version
 * @example
 * ```tsx
 * const useStyle = styleHookSingleton();
 * ///
 * useStyle('body { overflow: hidden}');
 */
var styleHookSingleton = function () {
    var sheet = stylesheetSingleton();
    return function (styles, isDynamic) {
        React__namespace.useEffect(function () {
            sheet.add(styles);
            return function () {
                sheet.remove();
            };
        }, [styles && isDynamic]);
    };
};

/**
 * create a Component to add styles on demand
 * - styles are added when first instance is mounted
 * - styles are removed when the last instance is unmounted
 * - changing styles in runtime does nothing unless dynamic is set. But with multiple components that can lead to the undefined behavior
 */
var styleSingleton = function () {
    var useStyle = styleHookSingleton();
    var Sheet = function (_a) {
        var styles = _a.styles, dynamic = _a.dynamic;
        useStyle(styles, dynamic);
        return null;
    };
    return Sheet;
};

var zeroGap = {
    left: 0,
    top: 0,
    right: 0,
    gap: 0,
};
var parse = function (x) { return parseInt(x || '', 10) || 0; };
var getOffset = function (gapMode) {
    var cs = window.getComputedStyle(document.body);
    var left = cs[gapMode === 'padding' ? 'paddingLeft' : 'marginLeft'];
    var top = cs[gapMode === 'padding' ? 'paddingTop' : 'marginTop'];
    var right = cs[gapMode === 'padding' ? 'paddingRight' : 'marginRight'];
    return [parse(left), parse(top), parse(right)];
};
var getGapWidth = function (gapMode) {
    if (gapMode === void 0) { gapMode = 'margin'; }
    if (typeof window === 'undefined') {
        return zeroGap;
    }
    var offsets = getOffset(gapMode);
    var documentWidth = document.documentElement.clientWidth;
    var windowWidth = window.innerWidth;
    return {
        left: offsets[0],
        top: offsets[1],
        right: offsets[2],
        gap: Math.max(0, windowWidth - documentWidth + offsets[2] - offsets[0]),
    };
};

var Style = styleSingleton();
var lockAttribute = 'data-scroll-locked';
// important tip - once we measure scrollBar width and remove them
// we could not repeat this operation
// thus we are using style-singleton - only the first "yet correct" style will be applied.
var getStyles = function (_a, allowRelative, gapMode, important) {
    var left = _a.left, top = _a.top, right = _a.right, gap = _a.gap;
    if (gapMode === void 0) { gapMode = 'margin'; }
    return "\n  .".concat(noScrollbarsClassName, " {\n   overflow: hidden ").concat(important, ";\n   padding-right: ").concat(gap, "px ").concat(important, ";\n  }\n  body[").concat(lockAttribute, "] {\n    overflow: hidden ").concat(important, ";\n    overscroll-behavior: contain;\n    ").concat([
        allowRelative && "position: relative ".concat(important, ";"),
        gapMode === 'margin' &&
            "\n    padding-left: ".concat(left, "px;\n    padding-top: ").concat(top, "px;\n    padding-right: ").concat(right, "px;\n    margin-left:0;\n    margin-top:0;\n    margin-right: ").concat(gap, "px ").concat(important, ";\n    "),
        gapMode === 'padding' && "padding-right: ".concat(gap, "px ").concat(important, ";"),
    ]
        .filter(Boolean)
        .join(''), "\n  }\n  \n  .").concat(zeroRightClassName, " {\n    right: ").concat(gap, "px ").concat(important, ";\n  }\n  \n  .").concat(fullWidthClassName, " {\n    margin-right: ").concat(gap, "px ").concat(important, ";\n  }\n  \n  .").concat(zeroRightClassName, " .").concat(zeroRightClassName, " {\n    right: 0 ").concat(important, ";\n  }\n  \n  .").concat(fullWidthClassName, " .").concat(fullWidthClassName, " {\n    margin-right: 0 ").concat(important, ";\n  }\n  \n  body[").concat(lockAttribute, "] {\n    ").concat(removedBarSizeVariable, ": ").concat(gap, "px;\n  }\n");
};
var getCurrentUseCounter = function () {
    var counter = parseInt(document.body.getAttribute(lockAttribute) || '0', 10);
    return isFinite(counter) ? counter : 0;
};
var useLockAttribute = function () {
    React__namespace.useEffect(function () {
        document.body.setAttribute(lockAttribute, (getCurrentUseCounter() + 1).toString());
        return function () {
            var newCounter = getCurrentUseCounter() - 1;
            if (newCounter <= 0) {
                document.body.removeAttribute(lockAttribute);
            }
            else {
                document.body.setAttribute(lockAttribute, newCounter.toString());
            }
        };
    }, []);
};
/**
 * Removes page scrollbar and blocks page scroll when mounted
 */
var RemoveScrollBar = function (_a) {
    var noRelative = _a.noRelative, noImportant = _a.noImportant, _b = _a.gapMode, gapMode = _b === void 0 ? 'margin' : _b;
    useLockAttribute();
    /*
     gap will be measured on every component mount
     however it will be used only by the "first" invocation
     due to singleton nature of <Style
     */
    var gap = React__namespace.useMemo(function () { return getGapWidth(gapMode); }, [gapMode]);
    return React__namespace.createElement(Style, { styles: getStyles(gap, !noRelative, gapMode, !noImportant ? '!important' : '') });
};

var passiveSupported = false;
if (typeof window !== 'undefined') {
    try {
        var options = Object.defineProperty({}, 'passive', {
            get: function () {
                passiveSupported = true;
                return true;
            },
        });
        // @ts-ignore
        window.addEventListener('test', options, options);
        // @ts-ignore
        window.removeEventListener('test', options, options);
    }
    catch (err) {
        passiveSupported = false;
    }
}
var nonPassive = passiveSupported ? { passive: false } : false;

var alwaysContainsScroll = function (node) {
    // textarea will always _contain_ scroll inside self. It only can be hidden
    return node.tagName === 'TEXTAREA';
};
var elementCanBeScrolled = function (node, overflow) {
    if (!(node instanceof Element)) {
        return false;
    }
    var styles = window.getComputedStyle(node);
    return (
    // not-not-scrollable
    styles[overflow] !== 'hidden' &&
        // contains scroll inside self
        !(styles.overflowY === styles.overflowX && !alwaysContainsScroll(node) && styles[overflow] === 'visible'));
};
var elementCouldBeVScrolled = function (node) { return elementCanBeScrolled(node, 'overflowY'); };
var elementCouldBeHScrolled = function (node) { return elementCanBeScrolled(node, 'overflowX'); };
var locationCouldBeScrolled = function (axis, node) {
    var ownerDocument = node.ownerDocument;
    var current = node;
    do {
        // Skip over shadow root
        if (typeof ShadowRoot !== 'undefined' && current instanceof ShadowRoot) {
            current = current.host;
        }
        var isScrollable = elementCouldBeScrolled(axis, current);
        if (isScrollable) {
            var _a = getScrollVariables(axis, current), scrollHeight = _a[1], clientHeight = _a[2];
            if (scrollHeight > clientHeight) {
                return true;
            }
        }
        current = current.parentNode;
    } while (current && current !== ownerDocument.body);
    return false;
};
var getVScrollVariables = function (_a) {
    var scrollTop = _a.scrollTop, scrollHeight = _a.scrollHeight, clientHeight = _a.clientHeight;
    return [
        scrollTop,
        scrollHeight,
        clientHeight,
    ];
};
var getHScrollVariables = function (_a) {
    var scrollLeft = _a.scrollLeft, scrollWidth = _a.scrollWidth, clientWidth = _a.clientWidth;
    return [
        scrollLeft,
        scrollWidth,
        clientWidth,
    ];
};
var elementCouldBeScrolled = function (axis, node) {
    return axis === 'v' ? elementCouldBeVScrolled(node) : elementCouldBeHScrolled(node);
};
var getScrollVariables = function (axis, node) {
    return axis === 'v' ? getVScrollVariables(node) : getHScrollVariables(node);
};
var getDirectionFactor = function (axis, direction) {
    /**
     * If the element's direction is rtl (right-to-left), then scrollLeft is 0 when the scrollbar is at its rightmost position,
     * and then increasingly negative as you scroll towards the end of the content.
     * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
     */
    return axis === 'h' && direction === 'rtl' ? -1 : 1;
};
var handleScroll = function (axis, endTarget, event, sourceDelta, noOverscroll) {
    var directionFactor = getDirectionFactor(axis, window.getComputedStyle(endTarget).direction);
    var delta = directionFactor * sourceDelta;
    // find scrollable target
    var target = event.target;
    var targetInLock = endTarget.contains(target);
    var shouldCancelScroll = false;
    var isDeltaPositive = delta > 0;
    var availableScroll = 0;
    var availableScrollTop = 0;
    do {
        if (!target) {
            break;
        }
        var _a = getScrollVariables(axis, target), position = _a[0], scroll_1 = _a[1], capacity = _a[2];
        var elementScroll = scroll_1 - capacity - directionFactor * position;
        if (position || elementScroll) {
            if (elementCouldBeScrolled(axis, target)) {
                availableScroll += elementScroll;
                availableScrollTop += position;
            }
        }
        var parent_1 = target.parentNode;
        // we will "bubble" from ShadowDom in case we are, or just to the parent in normal case
        // this is the same logic used in focus-lock
        target = (parent_1 && parent_1.nodeType === Node.DOCUMENT_FRAGMENT_NODE ? parent_1.host : parent_1);
    } while (
    // portaled content
    (!targetInLock && target !== document.body) ||
        // self content
        (targetInLock && (endTarget.contains(target) || endTarget === target)));
    // handle epsilon around 0 (non standard zoom levels)
    if (isDeltaPositive &&
        ((Math.abs(availableScroll) < 1) || (false))) {
        shouldCancelScroll = true;
    }
    else if (!isDeltaPositive &&
        ((Math.abs(availableScrollTop) < 1) || (false))) {
        shouldCancelScroll = true;
    }
    return shouldCancelScroll;
};

var getTouchXY = function (event) {
    return 'changedTouches' in event ? [event.changedTouches[0].clientX, event.changedTouches[0].clientY] : [0, 0];
};
var getDeltaXY = function (event) { return [event.deltaX, event.deltaY]; };
var extractRef = function (ref) {
    return ref && 'current' in ref ? ref.current : ref;
};
var deltaCompare = function (x, y) { return x[0] === y[0] && x[1] === y[1]; };
var generateStyle = function (id) { return "\n  .block-interactivity-".concat(id, " {pointer-events: none;}\n  .allow-interactivity-").concat(id, " {pointer-events: all;}\n"); };
var idCounter = 0;
var lockStack = [];
function RemoveScrollSideCar(props) {
    var shouldPreventQueue = React__namespace.useRef([]);
    var touchStartRef = React__namespace.useRef([0, 0]);
    var activeAxis = React__namespace.useRef();
    var id = React__namespace.useState(idCounter++)[0];
    var Style = React__namespace.useState(styleSingleton)[0];
    var lastProps = React__namespace.useRef(props);
    React__namespace.useEffect(function () {
        lastProps.current = props;
    }, [props]);
    React__namespace.useEffect(function () {
        if (props.inert) {
            document.body.classList.add("block-interactivity-".concat(id));
            var allow_1 = __spreadArray([props.lockRef.current], (props.shards || []).map(extractRef), true).filter(Boolean);
            allow_1.forEach(function (el) { return el.classList.add("allow-interactivity-".concat(id)); });
            return function () {
                document.body.classList.remove("block-interactivity-".concat(id));
                allow_1.forEach(function (el) { return el.classList.remove("allow-interactivity-".concat(id)); });
            };
        }
        return;
    }, [props.inert, props.lockRef.current, props.shards]);
    var shouldCancelEvent = React__namespace.useCallback(function (event, parent) {
        if (('touches' in event && event.touches.length === 2) || (event.type === 'wheel' && event.ctrlKey)) {
            return !lastProps.current.allowPinchZoom;
        }
        var touch = getTouchXY(event);
        var touchStart = touchStartRef.current;
        var deltaX = 'deltaX' in event ? event.deltaX : touchStart[0] - touch[0];
        var deltaY = 'deltaY' in event ? event.deltaY : touchStart[1] - touch[1];
        var currentAxis;
        var target = event.target;
        var moveDirection = Math.abs(deltaX) > Math.abs(deltaY) ? 'h' : 'v';
        // allow horizontal touch move on Range inputs. They will not cause any scroll
        if ('touches' in event && moveDirection === 'h' && target.type === 'range') {
            return false;
        }
        var canBeScrolledInMainDirection = locationCouldBeScrolled(moveDirection, target);
        if (!canBeScrolledInMainDirection) {
            return true;
        }
        if (canBeScrolledInMainDirection) {
            currentAxis = moveDirection;
        }
        else {
            currentAxis = moveDirection === 'v' ? 'h' : 'v';
            canBeScrolledInMainDirection = locationCouldBeScrolled(moveDirection, target);
            // other axis might be not scrollable
        }
        if (!canBeScrolledInMainDirection) {
            return false;
        }
        if (!activeAxis.current && 'changedTouches' in event && (deltaX || deltaY)) {
            activeAxis.current = currentAxis;
        }
        if (!currentAxis) {
            return true;
        }
        var cancelingAxis = activeAxis.current || currentAxis;
        return handleScroll(cancelingAxis, parent, event, cancelingAxis === 'h' ? deltaX : deltaY);
    }, []);
    var shouldPrevent = React__namespace.useCallback(function (_event) {
        var event = _event;
        if (!lockStack.length || lockStack[lockStack.length - 1] !== Style) {
            // not the last active
            return;
        }
        var delta = 'deltaY' in event ? getDeltaXY(event) : getTouchXY(event);
        var sourceEvent = shouldPreventQueue.current.filter(function (e) { return e.name === event.type && (e.target === event.target || event.target === e.shadowParent) && deltaCompare(e.delta, delta); })[0];
        // self event, and should be canceled
        if (sourceEvent && sourceEvent.should) {
            if (event.cancelable) {
                event.preventDefault();
            }
            return;
        }
        // outside or shard event
        if (!sourceEvent) {
            var shardNodes = (lastProps.current.shards || [])
                .map(extractRef)
                .filter(Boolean)
                .filter(function (node) { return node.contains(event.target); });
            var shouldStop = shardNodes.length > 0 ? shouldCancelEvent(event, shardNodes[0]) : !lastProps.current.noIsolation;
            if (shouldStop) {
                if (event.cancelable) {
                    event.preventDefault();
                }
            }
        }
    }, []);
    var shouldCancel = React__namespace.useCallback(function (name, delta, target, should) {
        var event = { name: name, delta: delta, target: target, should: should, shadowParent: getOutermostShadowParent(target) };
        shouldPreventQueue.current.push(event);
        setTimeout(function () {
            shouldPreventQueue.current = shouldPreventQueue.current.filter(function (e) { return e !== event; });
        }, 1);
    }, []);
    var scrollTouchStart = React__namespace.useCallback(function (event) {
        touchStartRef.current = getTouchXY(event);
        activeAxis.current = undefined;
    }, []);
    var scrollWheel = React__namespace.useCallback(function (event) {
        shouldCancel(event.type, getDeltaXY(event), event.target, shouldCancelEvent(event, props.lockRef.current));
    }, []);
    var scrollTouchMove = React__namespace.useCallback(function (event) {
        shouldCancel(event.type, getTouchXY(event), event.target, shouldCancelEvent(event, props.lockRef.current));
    }, []);
    React__namespace.useEffect(function () {
        lockStack.push(Style);
        props.setCallbacks({
            onScrollCapture: scrollWheel,
            onWheelCapture: scrollWheel,
            onTouchMoveCapture: scrollTouchMove,
        });
        document.addEventListener('wheel', shouldPrevent, nonPassive);
        document.addEventListener('touchmove', shouldPrevent, nonPassive);
        document.addEventListener('touchstart', scrollTouchStart, nonPassive);
        return function () {
            lockStack = lockStack.filter(function (inst) { return inst !== Style; });
            document.removeEventListener('wheel', shouldPrevent, nonPassive);
            document.removeEventListener('touchmove', shouldPrevent, nonPassive);
            document.removeEventListener('touchstart', scrollTouchStart, nonPassive);
        };
    }, []);
    var removeScrollBar = props.removeScrollBar, inert = props.inert;
    return (React__namespace.createElement(React__namespace.Fragment, null,
        inert ? React__namespace.createElement(Style, { styles: generateStyle(id) }) : null,
        removeScrollBar ? React__namespace.createElement(RemoveScrollBar, { noRelative: props.noRelative, gapMode: props.gapMode }) : null));
}
function getOutermostShadowParent(node) {
    var shadowParent = null;
    while (node !== null) {
        if (node instanceof ShadowRoot) {
            shadowParent = node.host;
            node = node.host;
        }
        node = node.parentNode;
    }
    return shadowParent;
}

var SideCar = exportSidecar(effectCar, RemoveScrollSideCar);

var ReactRemoveScroll = React__namespace.forwardRef(function (props, ref) { return (React__namespace.createElement(RemoveScroll, __assign({}, props, { ref: ref, sideCar: SideCar }))); });
ReactRemoveScroll.classNames = RemoveScroll.classNames;

var getDefaultParent = function (originalTarget) {
    if (typeof document === 'undefined') {
        return null;
    }
    var sampleTarget = Array.isArray(originalTarget) ? originalTarget[0] : originalTarget;
    return sampleTarget.ownerDocument.body;
};
var counterMap = new WeakMap();
var uncontrolledNodes = new WeakMap();
var markerMap = {};
var lockCount = 0;
var unwrapHost = function (node) {
    return node && (node.host || unwrapHost(node.parentNode));
};
var correctTargets = function (parent, targets) {
    return targets
        .map(function (target) {
        if (parent.contains(target)) {
            return target;
        }
        var correctedTarget = unwrapHost(target);
        if (correctedTarget && parent.contains(correctedTarget)) {
            return correctedTarget;
        }
        console.error('aria-hidden', target, 'in not contained inside', parent, '. Doing nothing');
        return null;
    })
        .filter(function (x) { return Boolean(x); });
};
/**
 * Marks everything except given node(or nodes) as aria-hidden
 * @param {Element | Element[]} originalTarget - elements to keep on the page
 * @param [parentNode] - top element, defaults to document.body
 * @param {String} [markerName] - a special attribute to mark every node
 * @param {String} [controlAttribute] - html Attribute to control
 * @return {Undo} undo command
 */
var applyAttributeToOthers = function (originalTarget, parentNode, markerName, controlAttribute) {
    var targets = correctTargets(parentNode, Array.isArray(originalTarget) ? originalTarget : [originalTarget]);
    if (!markerMap[markerName]) {
        markerMap[markerName] = new WeakMap();
    }
    var markerCounter = markerMap[markerName];
    var hiddenNodes = [];
    var elementsToKeep = new Set();
    var elementsToStop = new Set(targets);
    var keep = function (el) {
        if (!el || elementsToKeep.has(el)) {
            return;
        }
        elementsToKeep.add(el);
        keep(el.parentNode);
    };
    targets.forEach(keep);
    var deep = function (parent) {
        if (!parent || elementsToStop.has(parent)) {
            return;
        }
        Array.prototype.forEach.call(parent.children, function (node) {
            if (elementsToKeep.has(node)) {
                deep(node);
            }
            else {
                try {
                    var attr = node.getAttribute(controlAttribute);
                    var alreadyHidden = attr !== null && attr !== 'false';
                    var counterValue = (counterMap.get(node) || 0) + 1;
                    var markerValue = (markerCounter.get(node) || 0) + 1;
                    counterMap.set(node, counterValue);
                    markerCounter.set(node, markerValue);
                    hiddenNodes.push(node);
                    if (counterValue === 1 && alreadyHidden) {
                        uncontrolledNodes.set(node, true);
                    }
                    if (markerValue === 1) {
                        node.setAttribute(markerName, 'true');
                    }
                    if (!alreadyHidden) {
                        node.setAttribute(controlAttribute, 'true');
                    }
                }
                catch (e) {
                    console.error('aria-hidden: cannot operate on ', node, e);
                }
            }
        });
    };
    deep(parentNode);
    elementsToKeep.clear();
    lockCount++;
    return function () {
        hiddenNodes.forEach(function (node) {
            var counterValue = counterMap.get(node) - 1;
            var markerValue = markerCounter.get(node) - 1;
            counterMap.set(node, counterValue);
            markerCounter.set(node, markerValue);
            if (!counterValue) {
                if (!uncontrolledNodes.has(node)) {
                    node.removeAttribute(controlAttribute);
                }
                uncontrolledNodes.delete(node);
            }
            if (!markerValue) {
                node.removeAttribute(markerName);
            }
        });
        lockCount--;
        if (!lockCount) {
            // clear
            counterMap = new WeakMap();
            counterMap = new WeakMap();
            uncontrolledNodes = new WeakMap();
            markerMap = {};
        }
    };
};
/**
 * Marks everything except given node(or nodes) as aria-hidden
 * @param {Element | Element[]} originalTarget - elements to keep on the page
 * @param [parentNode] - top element, defaults to document.body
 * @param {String} [markerName] - a special attribute to mark every node
 * @return {Undo} undo command
 */
var hideOthers = function (originalTarget, parentNode, markerName) {
    if (markerName === void 0) { markerName = 'data-aria-hidden'; }
    var targets = Array.from(Array.isArray(originalTarget) ? originalTarget : [originalTarget]);
    var activeParentNode = getDefaultParent(originalTarget);
    if (!activeParentNode) {
        return function () { return null; };
    }
    // we should not hide aria-live elements - https://github.com/theKashey/aria-hidden/issues/10
    // and script elements, as they have no impact on accessibility.
    targets.push.apply(targets, Array.from(activeParentNode.querySelectorAll('[aria-live], script')));
    return applyAttributeToOthers(targets, activeParentNode, markerName, 'aria-hidden');
};

var DIALOG_NAME = "Dialog";
var [createDialogContext, createDialogScope] = createContextScope(DIALOG_NAME);
var [DialogProvider, useDialogContext] = createDialogContext(DIALOG_NAME);
var Dialog$1 = (props) => {
  const {
    __scopeDialog,
    children,
    open: openProp,
    defaultOpen,
    onOpenChange,
    modal = true
  } = props;
  const triggerRef = React__namespace.useRef(null);
  const contentRef = React__namespace.useRef(null);
  const [open, setOpen] = useControllableState({
    prop: openProp,
    defaultProp: defaultOpen ?? false,
    onChange: onOpenChange,
    caller: DIALOG_NAME
  });
  return /* @__PURE__ */ jsxRuntime.jsx(
    DialogProvider,
    {
      scope: __scopeDialog,
      triggerRef,
      contentRef,
      contentId: useId(),
      titleId: useId(),
      descriptionId: useId(),
      open,
      onOpenChange: setOpen,
      onOpenToggle: React__namespace.useCallback(() => setOpen((prevOpen) => !prevOpen), [setOpen]),
      modal,
      children
    }
  );
};
Dialog$1.displayName = DIALOG_NAME;
var TRIGGER_NAME = "DialogTrigger";
var DialogTrigger = React__namespace.forwardRef(
  (props, forwardedRef) => {
    const { __scopeDialog, ...triggerProps } = props;
    const context = useDialogContext(TRIGGER_NAME, __scopeDialog);
    const composedTriggerRef = useComposedRefs(forwardedRef, context.triggerRef);
    return /* @__PURE__ */ jsxRuntime.jsx(
      Primitive.button,
      {
        type: "button",
        "aria-haspopup": "dialog",
        "aria-expanded": context.open,
        "aria-controls": context.contentId,
        "data-state": getState(context.open),
        ...triggerProps,
        ref: composedTriggerRef,
        onClick: composeEventHandlers(props.onClick, context.onOpenToggle)
      }
    );
  }
);
DialogTrigger.displayName = TRIGGER_NAME;
var PORTAL_NAME = "DialogPortal";
var [PortalProvider, usePortalContext] = createDialogContext(PORTAL_NAME, {
  forceMount: void 0
});
var DialogPortal$1 = (props) => {
  const { __scopeDialog, forceMount, children, container } = props;
  const context = useDialogContext(PORTAL_NAME, __scopeDialog);
  return /* @__PURE__ */ jsxRuntime.jsx(PortalProvider, { scope: __scopeDialog, forceMount, children: React__namespace.Children.map(children, (child) => /* @__PURE__ */ jsxRuntime.jsx(Presence, { present: forceMount || context.open, children: /* @__PURE__ */ jsxRuntime.jsx(Portal$1, { asChild: true, container, children: child }) })) });
};
DialogPortal$1.displayName = PORTAL_NAME;
var OVERLAY_NAME = "DialogOverlay";
var DialogOverlay$1 = React__namespace.forwardRef(
  (props, forwardedRef) => {
    const portalContext = usePortalContext(OVERLAY_NAME, props.__scopeDialog);
    const { forceMount = portalContext.forceMount, ...overlayProps } = props;
    const context = useDialogContext(OVERLAY_NAME, props.__scopeDialog);
    return context.modal ? /* @__PURE__ */ jsxRuntime.jsx(Presence, { present: forceMount || context.open, children: /* @__PURE__ */ jsxRuntime.jsx(DialogOverlayImpl, { ...overlayProps, ref: forwardedRef }) }) : null;
  }
);
DialogOverlay$1.displayName = OVERLAY_NAME;
var Slot = createSlot("DialogOverlay.RemoveScroll");
var DialogOverlayImpl = React__namespace.forwardRef(
  (props, forwardedRef) => {
    const { __scopeDialog, ...overlayProps } = props;
    const context = useDialogContext(OVERLAY_NAME, __scopeDialog);
    return (
      // Make sure `Content` is scrollable even when it doesn't live inside `RemoveScroll`
      // ie. when `Overlay` and `Content` are siblings
      /* @__PURE__ */ jsxRuntime.jsx(ReactRemoveScroll, { as: Slot, allowPinchZoom: true, shards: [context.contentRef], children: /* @__PURE__ */ jsxRuntime.jsx(
        Primitive.div,
        {
          "data-state": getState(context.open),
          ...overlayProps,
          ref: forwardedRef,
          style: { pointerEvents: "auto", ...overlayProps.style }
        }
      ) })
    );
  }
);
var CONTENT_NAME = "DialogContent";
var DialogContent$1 = React__namespace.forwardRef(
  (props, forwardedRef) => {
    const portalContext = usePortalContext(CONTENT_NAME, props.__scopeDialog);
    const { forceMount = portalContext.forceMount, ...contentProps } = props;
    const context = useDialogContext(CONTENT_NAME, props.__scopeDialog);
    return /* @__PURE__ */ jsxRuntime.jsx(Presence, { present: forceMount || context.open, children: context.modal ? /* @__PURE__ */ jsxRuntime.jsx(DialogContentModal, { ...contentProps, ref: forwardedRef }) : /* @__PURE__ */ jsxRuntime.jsx(DialogContentNonModal, { ...contentProps, ref: forwardedRef }) });
  }
);
DialogContent$1.displayName = CONTENT_NAME;
var DialogContentModal = React__namespace.forwardRef(
  (props, forwardedRef) => {
    const context = useDialogContext(CONTENT_NAME, props.__scopeDialog);
    const contentRef = React__namespace.useRef(null);
    const composedRefs = useComposedRefs(forwardedRef, context.contentRef, contentRef);
    React__namespace.useEffect(() => {
      const content = contentRef.current;
      if (content) return hideOthers(content);
    }, []);
    return /* @__PURE__ */ jsxRuntime.jsx(
      DialogContentImpl,
      {
        ...props,
        ref: composedRefs,
        trapFocus: context.open,
        disableOutsidePointerEvents: true,
        onCloseAutoFocus: composeEventHandlers(props.onCloseAutoFocus, (event) => {
          event.preventDefault();
          context.triggerRef.current?.focus();
        }),
        onPointerDownOutside: composeEventHandlers(props.onPointerDownOutside, (event) => {
          const originalEvent = event.detail.originalEvent;
          const ctrlLeftClick = originalEvent.button === 0 && originalEvent.ctrlKey === true;
          const isRightClick = originalEvent.button === 2 || ctrlLeftClick;
          if (isRightClick) event.preventDefault();
        }),
        onFocusOutside: composeEventHandlers(
          props.onFocusOutside,
          (event) => event.preventDefault()
        )
      }
    );
  }
);
var DialogContentNonModal = React__namespace.forwardRef(
  (props, forwardedRef) => {
    const context = useDialogContext(CONTENT_NAME, props.__scopeDialog);
    const hasInteractedOutsideRef = React__namespace.useRef(false);
    const hasPointerDownOutsideRef = React__namespace.useRef(false);
    return /* @__PURE__ */ jsxRuntime.jsx(
      DialogContentImpl,
      {
        ...props,
        ref: forwardedRef,
        trapFocus: false,
        disableOutsidePointerEvents: false,
        onCloseAutoFocus: (event) => {
          props.onCloseAutoFocus?.(event);
          if (!event.defaultPrevented) {
            if (!hasInteractedOutsideRef.current) context.triggerRef.current?.focus();
            event.preventDefault();
          }
          hasInteractedOutsideRef.current = false;
          hasPointerDownOutsideRef.current = false;
        },
        onInteractOutside: (event) => {
          props.onInteractOutside?.(event);
          if (!event.defaultPrevented) {
            hasInteractedOutsideRef.current = true;
            if (event.detail.originalEvent.type === "pointerdown") {
              hasPointerDownOutsideRef.current = true;
            }
          }
          const target = event.target;
          const targetIsTrigger = context.triggerRef.current?.contains(target);
          if (targetIsTrigger) event.preventDefault();
          if (event.detail.originalEvent.type === "focusin" && hasPointerDownOutsideRef.current) {
            event.preventDefault();
          }
        }
      }
    );
  }
);
var DialogContentImpl = React__namespace.forwardRef(
  (props, forwardedRef) => {
    const { __scopeDialog, trapFocus, onOpenAutoFocus, onCloseAutoFocus, ...contentProps } = props;
    const context = useDialogContext(CONTENT_NAME, __scopeDialog);
    const contentRef = React__namespace.useRef(null);
    const composedRefs = useComposedRefs(forwardedRef, contentRef);
    useFocusGuards();
    return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
      /* @__PURE__ */ jsxRuntime.jsx(
        FocusScope,
        {
          asChild: true,
          loop: true,
          trapped: trapFocus,
          onMountAutoFocus: onOpenAutoFocus,
          onUnmountAutoFocus: onCloseAutoFocus,
          children: /* @__PURE__ */ jsxRuntime.jsx(
            DismissableLayer,
            {
              role: "dialog",
              id: context.contentId,
              "aria-describedby": context.descriptionId,
              "aria-labelledby": context.titleId,
              "data-state": getState(context.open),
              ...contentProps,
              ref: composedRefs,
              onDismiss: () => context.onOpenChange(false)
            }
          )
        }
      ),
      /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
        /* @__PURE__ */ jsxRuntime.jsx(TitleWarning, { titleId: context.titleId }),
        /* @__PURE__ */ jsxRuntime.jsx(DescriptionWarning, { contentRef, descriptionId: context.descriptionId })
      ] })
    ] });
  }
);
var TITLE_NAME = "DialogTitle";
var DialogTitle$1 = React__namespace.forwardRef(
  (props, forwardedRef) => {
    const { __scopeDialog, ...titleProps } = props;
    const context = useDialogContext(TITLE_NAME, __scopeDialog);
    return /* @__PURE__ */ jsxRuntime.jsx(Primitive.h2, { id: context.titleId, ...titleProps, ref: forwardedRef });
  }
);
DialogTitle$1.displayName = TITLE_NAME;
var DESCRIPTION_NAME = "DialogDescription";
var DialogDescription$1 = React__namespace.forwardRef(
  (props, forwardedRef) => {
    const { __scopeDialog, ...descriptionProps } = props;
    const context = useDialogContext(DESCRIPTION_NAME, __scopeDialog);
    return /* @__PURE__ */ jsxRuntime.jsx(Primitive.p, { id: context.descriptionId, ...descriptionProps, ref: forwardedRef });
  }
);
DialogDescription$1.displayName = DESCRIPTION_NAME;
var CLOSE_NAME = "DialogClose";
var DialogClose = React__namespace.forwardRef(
  (props, forwardedRef) => {
    const { __scopeDialog, ...closeProps } = props;
    const context = useDialogContext(CLOSE_NAME, __scopeDialog);
    return /* @__PURE__ */ jsxRuntime.jsx(
      Primitive.button,
      {
        type: "button",
        ...closeProps,
        ref: forwardedRef,
        onClick: composeEventHandlers(props.onClick, () => context.onOpenChange(false))
      }
    );
  }
);
DialogClose.displayName = CLOSE_NAME;
function getState(open) {
  return open ? "open" : "closed";
}
var TITLE_WARNING_NAME = "DialogTitleWarning";
var [WarningProvider, useWarningContext] = createContext2(TITLE_WARNING_NAME, {
  contentName: CONTENT_NAME,
  titleName: TITLE_NAME,
  docsSlug: "dialog"
});
var TitleWarning = ({ titleId }) => {
  const titleWarningContext = useWarningContext(TITLE_WARNING_NAME);
  const MESSAGE = `\`${titleWarningContext.contentName}\` requires a \`${titleWarningContext.titleName}\` for the component to be accessible for screen reader users.

If you want to hide the \`${titleWarningContext.titleName}\`, you can wrap it with our VisuallyHidden component.

For more information, see https://radix-ui.com/primitives/docs/components/${titleWarningContext.docsSlug}`;
  React__namespace.useEffect(() => {
    if (titleId) {
      const hasTitle = document.getElementById(titleId);
      if (!hasTitle) console.error(MESSAGE);
    }
  }, [MESSAGE, titleId]);
  return null;
};
var DESCRIPTION_WARNING_NAME = "DialogDescriptionWarning";
var DescriptionWarning = ({ contentRef, descriptionId }) => {
  const descriptionWarningContext = useWarningContext(DESCRIPTION_WARNING_NAME);
  const MESSAGE = `Warning: Missing \`Description\` or \`aria-describedby={undefined}\` for {${descriptionWarningContext.contentName}}.`;
  React__namespace.useEffect(() => {
    const describedById = contentRef.current?.getAttribute("aria-describedby");
    if (descriptionId && describedById) {
      const hasDescription = document.getElementById(descriptionId);
      if (!hasDescription) console.warn(MESSAGE);
    }
  }, [MESSAGE, contentRef, descriptionId]);
  return null;
};
var Root$1 = Dialog$1;
var Portal = DialogPortal$1;
var Overlay = DialogOverlay$1;
var Content = DialogContent$1;
var Title = DialogTitle$1;
var Description = DialogDescription$1;
var Close = DialogClose;

function cn(...inputs) {
    return tailwindMerge.twMerge(clsx.clsx(inputs));
}

const Dialog = Root$1;
const DialogPortal = Portal;
const DialogOverlay = React__namespace.forwardRef(({ className, ...props }, ref) => (jsxRuntime.jsx(Overlay, { ref: ref, className: cn("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", className), ...props })));
DialogOverlay.displayName = Overlay.displayName;
const DialogContent = React__namespace.forwardRef(({ className, children, ...props }, ref) => (jsxRuntime.jsxs(DialogPortal, { children: [jsxRuntime.jsx(DialogOverlay, {}), jsxRuntime.jsxs(Content, { ref: ref, className: cn("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", className), ...props, children: [children, jsxRuntime.jsxs(Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" }), jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })] })] })] })));
DialogContent.displayName = Content.displayName;
const DialogHeader = ({ className, ...props }) => (jsxRuntime.jsx("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props }));
DialogHeader.displayName = "DialogHeader";
const DialogTitle = React__namespace.forwardRef(({ className, ...props }, ref) => (jsxRuntime.jsx(Title, { ref: ref, className: cn("text-lg font-semibold leading-none tracking-tight", className), ...props })));
DialogTitle.displayName = Title.displayName;
const DialogDescription = React__namespace.forwardRef(({ className, ...props }, ref) => (jsxRuntime.jsx(Description, { ref: ref, className: cn("text-sm text-muted-foreground", className), ...props })));
DialogDescription.displayName = Description.displayName;

const buttonVariants = classVarianceAuthority.cva("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", {
    variants: {
        variant: {
            default: "bg-primary text-primary-foreground hover:bg-primary/90",
            destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
            outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
            secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
            ghost: "hover:bg-accent hover:text-accent-foreground",
            link: "text-primary underline-offset-4 hover:underline",
        },
        size: {
            default: "h-10 px-4 py-2",
            sm: "h-9 rounded-md px-3",
            lg: "h-11 rounded-md px-8",
            icon: "h-10 w-10",
        },
    },
    defaultVariants: {
        variant: "default",
        size: "default",
    },
});
const Button = React__namespace.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
    const Comp = asChild ? Slot$1 : "button";
    return (jsxRuntime.jsx(Comp, { className: cn(buttonVariants({ variant, size, className })), ref: ref, ...props }));
});
Button.displayName = "Button";

const Input = React__namespace.forwardRef(({ className, type, ...props }, ref) => {
    return (jsxRuntime.jsx("input", { type: type, className: cn("flex h-10 w-full rounded-md border border-gray-200 bg-white px-3 py-2 text-sm ring-offset-white file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-gray-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", className), ref: ref, ...props }));
});
Input.displayName = "Input";

var PROGRESS_NAME = "Progress";
var DEFAULT_MAX = 100;
var [createProgressContext, createProgressScope] = createContextScope(PROGRESS_NAME);
var [ProgressProvider, useProgressContext] = createProgressContext(PROGRESS_NAME);
var Progress$1 = React__namespace.forwardRef(
  (props, forwardedRef) => {
    const {
      __scopeProgress,
      value: valueProp = null,
      max: maxProp,
      getValueLabel = defaultGetValueLabel,
      ...progressProps
    } = props;
    if ((maxProp || maxProp === 0) && !isValidMaxNumber(maxProp)) {
      console.error(getInvalidMaxError(`${maxProp}`, "Progress"));
    }
    const max = isValidMaxNumber(maxProp) ? maxProp : DEFAULT_MAX;
    if (valueProp !== null && !isValidValueNumber(valueProp, max)) {
      console.error(getInvalidValueError(`${valueProp}`, "Progress"));
    }
    const value = isValidValueNumber(valueProp, max) ? valueProp : null;
    const valueLabel = isNumber(value) ? getValueLabel(value, max) : void 0;
    return /* @__PURE__ */ jsxRuntime.jsx(ProgressProvider, { scope: __scopeProgress, value, max, children: /* @__PURE__ */ jsxRuntime.jsx(
      Primitive.div,
      {
        "aria-valuemax": max,
        "aria-valuemin": 0,
        "aria-valuenow": isNumber(value) ? value : void 0,
        "aria-valuetext": valueLabel,
        role: "progressbar",
        "data-state": getProgressState(value, max),
        "data-value": value ?? void 0,
        "data-max": max,
        ...progressProps,
        ref: forwardedRef
      }
    ) });
  }
);
Progress$1.displayName = PROGRESS_NAME;
var INDICATOR_NAME = "ProgressIndicator";
var ProgressIndicator = React__namespace.forwardRef(
  (props, forwardedRef) => {
    const { __scopeProgress, ...indicatorProps } = props;
    const context = useProgressContext(INDICATOR_NAME, __scopeProgress);
    return /* @__PURE__ */ jsxRuntime.jsx(
      Primitive.div,
      {
        "data-state": getProgressState(context.value, context.max),
        "data-value": context.value ?? void 0,
        "data-max": context.max,
        ...indicatorProps,
        ref: forwardedRef
      }
    );
  }
);
ProgressIndicator.displayName = INDICATOR_NAME;
function defaultGetValueLabel(value, max) {
  return `${Math.round(value / max * 100)}%`;
}
function getProgressState(value, maxValue) {
  return value == null ? "indeterminate" : value === maxValue ? "complete" : "loading";
}
function isNumber(value) {
  return typeof value === "number";
}
function isValidMaxNumber(max) {
  return isNumber(max) && !isNaN(max) && max > 0;
}
function isValidValueNumber(value, max) {
  return isNumber(value) && !isNaN(value) && value <= max && value >= 0;
}
function getInvalidMaxError(propValue, componentName) {
  return `Invalid prop \`max\` of value \`${propValue}\` supplied to \`${componentName}\`. Only numbers greater than 0 are valid max values. Defaulting to \`${DEFAULT_MAX}\`.`;
}
function getInvalidValueError(propValue, componentName) {
  return `Invalid prop \`value\` of value \`${propValue}\` supplied to \`${componentName}\`. The \`value\` prop must be:
  - a positive number
  - less than the value passed to \`max\` (or ${DEFAULT_MAX} if no \`max\` prop is set)
  - \`null\` or \`undefined\` if the progress is indeterminate.

Defaulting to \`null\`.`;
}
var Root = Progress$1;
var Indicator = ProgressIndicator;

const Progress = React__namespace.forwardRef(({ className, value, ...props }, ref) => (jsxRuntime.jsx(Root, { ref: ref, className: cn("relative h-4 w-full overflow-hidden rounded-full bg-secondary", className), ...props, children: jsxRuntime.jsx(Indicator, { className: "h-full w-full flex-1 bg-primary transition-all", style: { transform: `translateX(-${100 - (value || 0)}%)` } }) })));
Progress.displayName = Root.displayName;

/**
 * Modern File Upload Modal - Next.js 15 + shadcn/ui
 */
const FILE_SOURCES = [
    { id: "device", label: "My Device", icon: lucideReact.Laptop },
    { id: "url", label: "Link (URL)", icon: lucideReact.Link },
    { id: "search", label: "Web Search", icon: lucideReact.Search },
    {
        id: "facebook",
        label: "Facebook",
        icon: () => (jsxRuntime.jsx("div", { className: "w-4 h-4 bg-blue-600 rounded text-white text-xs flex items-center justify-center font-bold", children: "f" })),
    },
    {
        id: "instagram",
        label: "Instagram",
        icon: () => (jsxRuntime.jsx("div", { className: "w-4 h-4 bg-gradient-to-br from-purple-500 to-pink-500 rounded text-white text-xs flex items-center justify-center font-bold", children: "ig" })),
    },
    {
        id: "drive",
        label: "Google Drive",
        icon: () => (jsxRuntime.jsx("div", { className: "w-4 h-4 bg-blue-500 rounded text-white text-xs flex items-center justify-center font-bold", children: "G" })),
    },
    {
        id: "dropbox",
        label: "Dropbox",
        icon: () => (jsxRuntime.jsx("div", { className: "w-4 h-4 bg-blue-700 rounded text-white text-xs flex items-center justify-center font-bold", children: "D" })),
    },
];
function FileUploadModal({ isOpen, onClose, onFileSelect, config, options = {}, multiple = false, accept = "*/*", title = "Upload Files", }) {
    const [activeSource, setActiveSource] = React.useState("device");
    const [viewMode, setViewMode] = React.useState("select");
    const [selectedFiles, setSelectedFiles] = React.useState([]);
    const [uploadingFiles, setUploadingFiles] = React.useState([]);
    const [uploadFilter, setUploadFilter] = React.useState("all");
    const [searchQuery, setSearchQuery] = React.useState("");
    const [isDragOver, setIsDragOver] = React.useState(false);
    const [urlInput, setUrlInput] = React.useState("");
    const [isUrlUploading, setIsUrlUploading] = React.useState(false);
    const fileInputRef = React.useRef(null);
    const uploadClient = new FileUploadClient(config);
    // Reset state when modal opens/closes
    React.useEffect(() => {
        if (!isOpen) {
            setViewMode("select");
            setSelectedFiles([]);
            setUploadingFiles([]);
            setSearchQuery("");
            setActiveSource("device");
            setUrlInput("");
            setIsUrlUploading(false);
        }
    }, [isOpen]);
    const handleFileSelect = React.useCallback((files) => {
        const fileArray = Array.from(files);
        const newFiles = fileArray.map((file, index) => ({
            id: `${Date.now()}-${index}`,
            file,
            name: file.name,
            size: file.size,
            type: file.type,
            preview: file.type.startsWith("image/")
                ? URL.createObjectURL(file)
                : undefined,
        }));
        if (multiple) {
            setSelectedFiles((prev) => [...prev, ...newFiles]);
        }
        else {
            setSelectedFiles(newFiles.slice(0, 1));
        }
        setViewMode("selected");
    }, [multiple]);
    const handleDeviceUpload = () => {
        fileInputRef.current?.click();
    };
    const handleFileInputChange = (e) => {
        if (e.target.files && e.target.files.length > 0) {
            handleFileSelect(e.target.files);
        }
    };
    const handleDragOver = (e) => {
        e.preventDefault();
        setIsDragOver(true);
    };
    const handleDragLeave = (e) => {
        e.preventDefault();
        setIsDragOver(false);
    };
    const handleDrop = (e) => {
        e.preventDefault();
        setIsDragOver(false);
        if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
            handleFileSelect(e.dataTransfer.files);
        }
    };
    const handlePaste = React.useCallback((e) => {
        if (e.clipboardData?.files && e.clipboardData.files.length > 0) {
            handleFileSelect(e.clipboardData.files);
        }
    }, [handleFileSelect]);
    React.useEffect(() => {
        if (isOpen && viewMode === "select") {
            document.addEventListener("paste", handlePaste);
            return () => document.removeEventListener("paste", handlePaste);
        }
    }, [isOpen, viewMode, handlePaste]);
    const removeSelectedFile = (id) => {
        setSelectedFiles((prev) => prev.filter((file) => file.id !== id));
        if (selectedFiles.length === 1) {
            setViewMode("select");
        }
    };
    const deselectAll = () => {
        setSelectedFiles([]);
        setViewMode("select");
    };
    const uploadMore = () => {
        setViewMode("select");
    };
    const handleUrlUpload = async () => {
        if (!urlInput.trim() || isUrlUploading)
            return;
        setIsUrlUploading(true);
        try {
            // Validate URL format
            try {
                new URL(urlInput);
            }
            catch {
                throw new Error("Please enter a valid URL");
            }
            // Download file info and create a preview (don't upload yet)
            const response = await fetch(urlInput, { method: "HEAD" });
            if (!response.ok) {
                throw new Error(`Failed to access URL: ${response.status} ${response.statusText}`);
            }
            // Extract file information
            const contentType = response.headers.get("content-type") || "application/octet-stream";
            const contentLength = parseInt(response.headers.get("content-length") || "0");
            const filename = urlInput.split("/").pop()?.split("?")[0] || "downloaded-file";
            // Validate file size if available
            const maxFileSize = config.maxFileSize || 50 * 1024 * 1024; // Default 50MB
            if (contentLength > 0 && contentLength > maxFileSize) {
                throw new Error(`File size (${Math.round(contentLength / 1024)} KB) exceeds maximum allowed size (${Math.round(maxFileSize / 1024)} KB)`);
            }
            // Validate file type
            if (config.allowedTypes && config.allowedTypes.length > 0) {
                const isAllowed = config.allowedTypes.some((allowedType) => {
                    if (allowedType === "*/*")
                        return true;
                    if (allowedType.includes("*")) {
                        const baseType = allowedType.split("/")[0];
                        return contentType.startsWith(baseType + "/");
                    }
                    return allowedType === contentType;
                });
                if (!isAllowed) {
                    throw new Error(`File type '${contentType}' is not allowed`);
                }
            }
            // Create a "virtual" file object for preview
            const virtualFile = {
                id: `url-${Date.now()}`,
                file: new File([], filename, { type: contentType }), // Empty file for now
                name: filename,
                size: contentLength,
                type: contentType,
                preview: contentType.startsWith("image/") ? urlInput : undefined,
                isFromUrl: true,
                sourceUrl: urlInput,
            };
            // Add to selected files (same as local files)
            if (multiple) {
                setSelectedFiles((prev) => [...prev, virtualFile]);
            }
            else {
                setSelectedFiles([virtualFile]);
            }
            // Switch to selected view (same as local files)
            setViewMode("selected");
            // Clear URL input
            setUrlInput("");
        }
        catch (error) {
            const errorMessage = error instanceof Error ? error.message : "Failed to process URL";
            console.error("URL processing failed:", error);
            alert(errorMessage); // Show error to user
        }
        finally {
            setIsUrlUploading(false);
        }
    };
    const startUpload = async () => {
        const filesToUpload = selectedFiles.map((file) => ({
            ...file,
            progress: 0,
            status: "uploading",
        }));
        setUploadingFiles(filesToUpload);
        setViewMode("uploading");
        // Upload files one by one
        for (let i = 0; i < filesToUpload.length; i++) {
            const file = filesToUpload[i];
            try {
                let result;
                if (file.isFromUrl && file.sourceUrl) {
                    // Upload from URL
                    result = await uploadClient.uploadFromUrl(file.sourceUrl, {
                        ...options,
                        filename: file.name, // Use the detected filename
                        onProgress: (progress) => {
                            setUploadingFiles((prev) => prev.map((f) => (f.id === file.id ? { ...f, progress } : f)));
                        },
                    });
                }
                else {
                    // Upload local file
                    result = await uploadClient.uploadFile(file.file, {
                        ...options,
                        onProgress: (progress) => {
                            setUploadingFiles((prev) => prev.map((f) => (f.id === file.id ? { ...f, progress } : f)));
                        },
                    });
                }
                setUploadingFiles((prev) => prev.map((f) => f.id === file.id
                    ? { ...f, status: "completed", progress: 100, result }
                    : f));
                // Call the onFileSelect callback for completed uploads
                onFileSelect(result.downloadUrl, result);
            }
            catch (error) {
                setUploadingFiles((prev) => prev.map((f) => f.id === file.id
                    ? {
                        ...f,
                        status: "failed",
                        error: error instanceof Error ? error.message : "Upload failed",
                    }
                    : f));
            }
        }
    };
    const filteredUploadingFiles = uploadingFiles.filter((file) => {
        if (uploadFilter === "all")
            return true;
        return file.status === uploadFilter;
    });
    const completedCount = uploadingFiles.filter((f) => f.status === "completed").length;
    const totalCount = uploadingFiles.length;
    const formatFileSize = (bytes) => {
        if (bytes === 0)
            return "0 Bytes";
        const k = 1024;
        const sizes = ["Bytes", "KB", "MB", "GB"];
        const i = Math.floor(Math.log(bytes) / Math.log(k));
        return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
    };
    const renderSidebar = () => (jsxRuntime.jsx("div", { className: "w-16 bg-gray-200 border-r border-gray-300 flex flex-col items-center py-4 space-y-2", children: FILE_SOURCES.map((source) => {
            const IconComponent = source.icon;
            const isActive = activeSource === source.id;
            const isClickable = source.id === "device" || source.id === "url";
            return (jsxRuntime.jsx("button", { onClick: () => isClickable && setActiveSource(source.id), disabled: !isClickable, className: `
              w-10 h-10 rounded-lg flex items-center justify-center transition-colors
              ${isActive && isClickable
                    ? "bg-blue-500 text-white"
                    : isClickable
                        ? "bg-white hover:bg-gray-100 text-gray-600"
                        : "bg-gray-100 text-gray-400 cursor-not-allowed"}
              border border-gray-300
            `, title: source.label, children: jsxRuntime.jsx(IconComponent, {}) }, source.id));
        }) }));
    const renderSelectView = () => (jsxRuntime.jsx("div", { className: "flex-1 flex flex-col", children: jsxRuntime.jsx("div", { className: "flex-1 flex items-center justify-center p-8", children: jsxRuntime.jsx("div", { className: `
            w-full max-w-md border-2 border-dashed rounded-lg p-12 text-center transition-colors
            ${isDragOver
                    ? "border-blue-500 bg-blue-50"
                    : "border-gray-300 bg-white"}
          `, onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, children: jsxRuntime.jsxs("div", { className: "flex flex-col items-center space-y-4", children: [jsxRuntime.jsxs("div", { className: "w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center", children: [jsxRuntime.jsx(lucideReact.FileText, { className: "w-8 h-8 text-gray-400" }), jsxRuntime.jsx(lucideReact.Plus, { className: "w-4 h-4 text-gray-400 -ml-2 -mt-2" })] }), jsxRuntime.jsxs("div", { className: "space-y-2", children: [jsxRuntime.jsx("h3", { className: "text-lg font-medium text-gray-900", children: "Select Files to Upload" }), jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "or Drag and Drop, Copy and Paste Files" })] }), activeSource === "device" && (jsxRuntime.jsx(Button, { onClick: handleDeviceUpload, className: "bg-blue-500 hover:bg-blue-600 text-white", children: "Choose Files" })), activeSource === "url" && (jsxRuntime.jsxs("div", { className: "w-full space-y-3", children: [jsxRuntime.jsx(Input, { placeholder: "https://example.com/image.jpg", value: urlInput, onChange: (e) => setUrlInput(e.target.value), onKeyPress: (e) => {
                                        if (e.key === "Enter" && !isUrlUploading) {
                                            handleUrlUpload();
                                        }
                                    }, className: "w-full", disabled: isUrlUploading }), jsxRuntime.jsx(Button, { onClick: handleUrlUpload, disabled: !urlInput.trim() || isUrlUploading, className: "w-full bg-blue-500 hover:bg-blue-600 text-white disabled:opacity-50", children: isUrlUploading ? (jsxRuntime.jsxs("div", { className: "flex items-center space-x-2", children: [jsxRuntime.jsx("div", { className: "animate-spin rounded-full h-4 w-4 border-b-2 border-white" }), jsxRuntime.jsx("span", { children: "Processing..." })] })) : ("Add from URL") }), jsxRuntime.jsx("p", { className: "text-xs text-gray-500 text-center", children: "Paste a web URL to preview the file before uploading" })] }))] }) }) }) }));
    const renderSelectedView = () => (jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col", children: [jsxRuntime.jsxs("div", { className: "p-4 border-b border-gray-200 flex items-center justify-between", children: [jsxRuntime.jsx("h3", { className: "text-lg font-medium text-gray-900", children: "Selected Files" }), jsxRuntime.jsxs("div", { className: "flex items-center space-x-2", children: [jsxRuntime.jsx(Input, { placeholder: "Search files...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), className: "w-48" }), jsxRuntime.jsx(lucideReact.Filter, { className: "w-4 h-4 text-gray-400" })] })] }), jsxRuntime.jsx("div", { className: "flex-1 p-4 overflow-y-auto", children: jsxRuntime.jsx("div", { className: "space-y-2", children: selectedFiles
                        .filter((file) => file.name.toLowerCase().includes(searchQuery.toLowerCase()))
                        .map((file) => (jsxRuntime.jsxs("div", { className: "flex items-center space-x-3 p-3 bg-white border border-gray-200 rounded-lg", children: [jsxRuntime.jsx("div", { className: "w-10 h-10 bg-gray-100 rounded flex items-center justify-center flex-shrink-0", children: file.preview ? (jsxRuntime.jsx("img", { src: file.preview, alt: file.name, className: "w-full h-full object-cover rounded" })) : (jsxRuntime.jsx(lucideReact.FileText, { className: "w-5 h-5 text-gray-400" })) }), jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntime.jsxs("div", { className: "flex items-center space-x-2", children: [jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-900 truncate whitespace-normal", children: file.name }), file.isFromUrl && (jsxRuntime.jsxs("span", { className: "inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 text-blue-800", children: [jsxRuntime.jsx(lucideReact.Link, { className: "w-3 h-3 mr-1" }), "URL"] }))] }), jsxRuntime.jsxs("p", { className: "text-xs text-gray-500", children: [file.size > 0 ? formatFileSize(file.size) : "Size unknown", " ", "\u2022 ", file.type] }), file.isFromUrl && file.sourceUrl && (jsxRuntime.jsxs("p", { className: "text-xs text-blue-500 truncate whitespace-normal", title: file.sourceUrl, children: ["Source: ", file.sourceUrl] }))] }), jsxRuntime.jsx("button", { onClick: () => removeSelectedFile(file.id), className: "p-1 text-gray-400 hover:text-red-500 transition-colors", children: jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" }) })] }, file.id))) }) }), jsxRuntime.jsxs("div", { className: "p-4 border-t border-gray-200 flex items-center justify-between", children: [jsxRuntime.jsxs("div", { className: "flex space-x-2", children: [jsxRuntime.jsx(Button, { variant: "outline", onClick: deselectAll, children: "Deselect All" }), jsxRuntime.jsx(Button, { variant: "outline", onClick: uploadMore, children: "Upload More" })] }), jsxRuntime.jsxs(Button, { onClick: startUpload, className: "bg-blue-500 hover:bg-blue-600 text-white", disabled: selectedFiles.length === 0, children: ["Upload (", selectedFiles.length, ")"] })] })] }));
    const renderUploadingView = () => (jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col", children: [jsxRuntime.jsxs("div", { className: "p-4 border-b border-gray-200", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-4", children: [jsxRuntime.jsxs("h3", { className: "text-lg font-medium text-gray-900", children: ["Uploaded ", completedCount, "/", totalCount] }), jsxRuntime.jsx("button", { onClick: () => setViewMode("select"), className: "px-3 py-1 text-sm bg-blue-500 hover:bg-blue-600 text-white rounded transition-colors", children: "Upload Again" })] }), jsxRuntime.jsx("div", { className: "flex space-x-1 bg-gray-100 rounded-lg p-1", children: ["all", "completed", "failed"].map((filter) => (jsxRuntime.jsxs("button", { onClick: () => setUploadFilter(filter), className: `
                px-3 py-1 rounded text-sm font-medium transition-colors capitalize
                ${uploadFilter === filter
                                ? "bg-white text-gray-900 shadow-sm"
                                : "text-gray-600 hover:text-gray-900"}
              `, children: [filter, " ", filter === "all" ? "Uploads" : ""] }, filter))) })] }), jsxRuntime.jsx("div", { className: "flex-1 p-4 overflow-y-auto", children: jsxRuntime.jsx("div", { className: "space-y-3", children: filteredUploadingFiles.map((file) => (jsxRuntime.jsxs("div", { className: "p-4 bg-white border border-gray-200 rounded-lg", children: [jsxRuntime.jsxs("div", { className: "flex items-center space-x-3 mb-3", children: [jsxRuntime.jsx("div", { className: "w-10 h-10 bg-gray-100 rounded flex items-center justify-center flex-shrink-0", children: file.preview ? (jsxRuntime.jsx("img", { src: file.preview, alt: file.name, className: "w-full h-full object-cover rounded" })) : (jsxRuntime.jsx(lucideReact.FileText, { className: "w-5 h-5 text-gray-400" })) }), jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-900 truncate whitespace-normal", children: file.name }), jsxRuntime.jsx("p", { className: "text-xs text-gray-500", children: formatFileSize(file.size) }), file.isFromUrl && file.sourceUrl && (jsxRuntime.jsxs("p", { className: "text-xs text-blue-500 truncate whitespace-normal", title: file.sourceUrl, children: ["Source: ", file.sourceUrl] }))] }), jsxRuntime.jsxs("div", { className: "flex items-center space-x-2", children: [file.status === "uploading" && (jsxRuntime.jsx(lucideReact.Clock, { className: "w-4 h-4 text-blue-500" })), file.status === "completed" && (jsxRuntime.jsx(lucideReact.CheckCircle, { className: "w-4 h-4 text-green-500" })), file.status === "failed" && (jsxRuntime.jsx(lucideReact.AlertCircle, { className: "w-4 h-4 text-red-500" })), file.status === "completed" && file.result && (jsxRuntime.jsx("div", { className: "flex space-x-1", children: jsxRuntime.jsx("button", { onClick: () => window.open(`${config.baseUrl}${file.result.previewUrl}`, "_blank"), className: "p-1 text-gray-400 hover:text-blue-500 transition-colors", title: "Preview", children: jsxRuntime.jsx(lucideReact.Eye, { className: "w-4 h-4" }) }) })), file.status === "failed" && (jsxRuntime.jsx("button", { onClick: () => {
                                                    // Retry upload for failed files
                                                    const fileToRetry = selectedFiles.find((f) => f.id === file.id) || file;
                                                    setSelectedFiles([fileToRetry]);
                                                    setViewMode("selected");
                                                }, className: "px-2 py-1 text-xs bg-red-100 hover:bg-red-200 text-red-700 rounded transition-colors", title: "Retry Upload", children: "Retry" }))] })] }), file.status === "uploading" && (jsxRuntime.jsxs("div", { className: "space-y-1", children: [jsxRuntime.jsx(Progress, { value: file.progress, className: "h-2" }), jsxRuntime.jsxs("p", { className: "text-xs text-gray-500", children: [file.progress, "% uploaded"] })] })), file.status === "failed" && file.error && (jsxRuntime.jsx("p", { className: "text-xs text-red-500 mt-1", children: file.error }))] }, file.id))) }) })] }));
    return (jsxRuntime.jsx(Dialog, { open: isOpen, onOpenChange: onClose, children: jsxRuntime.jsxs(DialogContent, { className: "max-w-4xl h-[600px] p-0 bg-gray-100", children: [jsxRuntime.jsx(DialogHeader, { className: "sr-only", children: jsxRuntime.jsx(DialogTitle, { children: title }) }), jsxRuntime.jsxs("div", { className: "flex h-full", children: [renderSidebar(), viewMode === "select" && renderSelectView(), viewMode === "selected" && renderSelectedView(), viewMode === "uploading" && renderUploadingView()] }), jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", multiple: multiple, accept: accept, onChange: handleFileInputChange, className: "hidden" })] }) }));
}

/**
 * Modern File Upload Button - Next.js 15 + shadcn/ui
 * Trigger button that opens the file upload modal
 */
function FileUploadButton({ config, onFileSelect, options = {}, multiple = false, accept = '*/*', title = 'Upload Files', variant = 'default', size = 'default', className, children, disabled = false }) {
    const [isModalOpen, setIsModalOpen] = React.useState(false);
    const handleFileSelect = (fileUrl, fileData) => {
        onFileSelect(fileUrl, fileData);
        if (!multiple) {
            setIsModalOpen(false);
        }
    };
    const handleOpenModal = () => {
        if (!disabled) {
            setIsModalOpen(true);
        }
    };
    return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs(Button, { variant: variant, size: size, className: cn('gap-2', className), onClick: handleOpenModal, disabled: disabled, children: [jsxRuntime.jsx(lucideReact.Upload, { className: "h-4 w-4" }), children || 'Upload Files'] }), jsxRuntime.jsx(FileUploadModal, { isOpen: isModalOpen, onClose: () => setIsModalOpen(false), onFileSelect: handleFileSelect, config: config, options: options, multiple: multiple, accept: accept, title: title })] }));
}

/**
 * React Hook for File Upload
 * Production-ready React hook for Health Ecosystem file uploads
 */
function useFileUpload(config, options = {}) {
    const clientRef = React.useRef();
    const fileInputRef = React.useRef(null);
    // Initialize client
    if (!clientRef.current) {
        clientRef.current = new FileUploadClient(config);
    }
    const [state, setState] = React.useState({
        isUploading: false,
        progress: {
            progress: 0,
            loaded: 0,
            total: 0
        },
        isCancelled: false
    });
    // Update auth token when config changes
    React.useEffect(() => {
        if (clientRef.current && config.authToken) {
            clientRef.current.updateAuthToken(config.authToken);
        }
    }, [config.authToken]);
    const reset = React.useCallback(() => {
        setState({
            isUploading: false,
            progress: {
                progress: 0,
                loaded: 0,
                total: 0
            },
            isCancelled: false,
            result: undefined,
            error: undefined
        });
    }, []);
    const cancel = React.useCallback(() => {
        if (clientRef.current && state.isUploading) {
            clientRef.current.cancelUpload();
            setState(prev => ({
                ...prev,
                isUploading: false,
                isCancelled: true
            }));
        }
    }, [state.isUploading]);
    const upload = React.useCallback(async (files, uploadOptions = {}) => {
        if (!clientRef.current) {
            throw new Error('FileUploadClient not initialized');
        }
        const fileArray = Array.isArray(files) ? files : [files];
        const mergedOptions = {
            category: 'other',
            ...options,
            ...uploadOptions,
            onStart: () => {
                setState(prev => ({
                    ...prev,
                    isUploading: true,
                    isCancelled: false,
                    error: undefined,
                    result: undefined
                }));
                uploadOptions.onStart?.();
                options.onStart?.();
            },
            onProgress: (progress) => {
                setState(prev => ({
                    ...prev,
                    progress: {
                        ...prev.progress,
                        progress
                    }
                }));
                uploadOptions.onProgress?.(progress);
                options.onProgress?.(progress);
            },
            onSuccess: (result) => {
                setState(prev => ({
                    ...prev,
                    isUploading: false,
                    result
                }));
                uploadOptions.onSuccess?.(result);
                options.onSuccess?.(result);
            },
            onError: (error) => {
                setState(prev => ({
                    ...prev,
                    isUploading: false,
                    error
                }));
                uploadOptions.onError?.(error);
                options.onError?.(error);
            }
        };
        try {
            if (fileArray.length === 1) {
                const result = await clientRef.current.uploadFile(fileArray[0], mergedOptions);
                return result;
            }
            else {
                const results = await clientRef.current.uploadFiles(fileArray, mergedOptions);
                return results;
            }
        }
        catch (error) {
            throw error;
        }
    }, [options]);
    const handleFileChange = React.useCallback((event) => {
        const files = event.target.files;
        if (files && files.length > 0) {
            const fileArray = Array.from(files);
            if (options.autoUpload) {
                upload(fileArray).catch(console.error);
            }
        }
        // Reset input value to allow selecting the same file again
        event.target.value = '';
    }, [upload, options.autoUpload]);
    const openFilePicker = React.useCallback(() => {
        fileInputRef.current?.click();
    }, []);
    const getInputProps = React.useCallback(() => ({
        type: 'file',
        accept: options.accept,
        multiple: options.multiple,
        onChange: handleFileChange,
        style: { display: 'none' }
    }), [options.accept, options.multiple, handleFileChange]);
    return {
        state,
        upload,
        cancel,
        reset,
        openFilePicker,
        getInputProps,
        client: clientRef.current
    };
}
/**
 * Hook for drag and drop file upload
 */
function useDropzone(config, options = {}) {
    const fileUpload = useFileUpload(config, options);
    const [isDragActive, setIsDragActive] = React.useState(false);
    const dragCounterRef = React.useRef(0);
    const handleDragEnter = React.useCallback((event) => {
        event.preventDefault();
        event.stopPropagation();
        dragCounterRef.current++;
        if (event.dataTransfer.items && event.dataTransfer.items.length > 0) {
            setIsDragActive(true);
        }
    }, []);
    const handleDragLeave = React.useCallback((event) => {
        event.preventDefault();
        event.stopPropagation();
        dragCounterRef.current--;
        if (dragCounterRef.current === 0) {
            setIsDragActive(false);
        }
    }, []);
    const handleDragOver = React.useCallback((event) => {
        event.preventDefault();
        event.stopPropagation();
    }, []);
    const handleDrop = React.useCallback((event) => {
        event.preventDefault();
        event.stopPropagation();
        setIsDragActive(false);
        dragCounterRef.current = 0;
        const files = Array.from(event.dataTransfer.files);
        if (files.length > 0) {
            if (options.autoUpload) {
                fileUpload.upload(files).catch(console.error);
            }
        }
    }, [fileUpload, options.autoUpload]);
    const getDropzoneProps = React.useCallback(() => ({
        onDragEnter: handleDragEnter,
        onDragLeave: handleDragLeave,
        onDragOver: handleDragOver,
        onDrop: handleDrop
    }), [handleDragEnter, handleDragLeave, handleDragOver, handleDrop]);
    return {
        ...fileUpload,
        isDragActive,
        getDropzoneProps
    };
}

const FileUploader = ({ config, options, multiple = false, accept, enableDropzone = true, autoUpload = false, showPreview = true, className = '', style, onSuccess, onError, onProgress, onFilesSelected, children }) => {
    const fileInputRef = React.useRef(null);
    const [selectedFiles, setSelectedFiles] = React.useState([]);
    const [previewUrls, setPreviewUrls] = React.useState([]);
    const hookOptions = {
        ...options,
        multiple,
        accept,
        autoUpload, // Use the autoUpload prop
        onSuccess: (result) => {
            // Clear files after successful upload
            clearFiles();
            onSuccess?.(result);
        },
        onError,
        onProgress
    };
    // Use separate hooks to avoid type inference issues
    const dropzoneHook = useDropzone(config, hookOptions);
    const fileUploadHook = useFileUpload(config, hookOptions);
    // Select the appropriate hook based on enableDropzone
    const selectedHook = enableDropzone ? dropzoneHook : fileUploadHook;
    const { state, upload: hookUpload, cancel, reset } = selectedHook;
    // Type-safe access to dropzone-specific properties
    const isDragActive = enableDropzone ? dropzoneHook.isDragActive : false;
    const getDropzoneProps = enableDropzone
        ? dropzoneHook.getDropzoneProps
        : () => ({});
    // File management functions
    const clearFiles = React.useCallback(() => {
        setSelectedFiles([]);
        // Clean up preview URLs
        previewUrls.forEach(url => URL.revokeObjectURL(url));
        setPreviewUrls([]);
    }, [previewUrls]);
    const removeFile = React.useCallback((index) => {
        setSelectedFiles(prev => prev.filter((_, i) => i !== index));
        setPreviewUrls(prev => {
            const newUrls = prev.filter((_, i) => i !== index);
            // Clean up the removed URL
            if (prev[index]) {
                URL.revokeObjectURL(prev[index]);
            }
            return newUrls;
        });
    }, []);
    const handleFileSelection = React.useCallback((files) => {
        setSelectedFiles(files);
        onFilesSelected?.(files);
        if (showPreview) {
            // Clean up old preview URLs
            previewUrls.forEach(url => URL.revokeObjectURL(url));
            // Create new preview URLs for images
            const newUrls = files.map(file => {
                if (file.type.startsWith('image/')) {
                    return URL.createObjectURL(file);
                }
                return '';
            });
            setPreviewUrls(newUrls);
        }
    }, [showPreview, previewUrls, onFilesSelected]);
    // Override the hook's file input handler
    const handleFileInputChange = React.useCallback((event) => {
        const files = event.target.files;
        if (files && files.length > 0) {
            const fileArray = Array.from(files);
            handleFileSelection(fileArray);
        }
        // Reset input value to allow selecting the same file again
        event.target.value = '';
    }, [handleFileSelection]);
    // Override dropzone drop handler
    const handleDrop = React.useCallback((event) => {
        event.preventDefault();
        event.stopPropagation();
        const files = Array.from(event.dataTransfer.files);
        if (files.length > 0) {
            handleFileSelection(files);
        }
    }, [handleFileSelection]);
    const openFilePicker = React.useCallback(() => {
        fileInputRef.current?.click();
    }, []);
    const upload = React.useCallback(async (filesToUpload) => {
        const files = filesToUpload || selectedFiles;
        if (files.length === 0) {
            throw new Error('No files selected');
        }
        return await hookUpload(files);
    }, [selectedFiles, hookUpload]);
    const resetAll = React.useCallback(() => {
        reset();
        clearFiles();
    }, [reset, clearFiles]);
    const renderProps = {
        isUploading: state.isUploading,
        progress: state.progress.progress,
        result: state.result,
        error: state.error,
        isDragActive,
        selectedFiles,
        openFilePicker,
        upload,
        cancel,
        reset: resetAll,
        clearFiles,
        removeFile
    };
    // Custom render function
    if (children) {
        return (jsxRuntime.jsxs("div", { className: className, style: style, children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", accept: accept, multiple: multiple, onChange: handleFileInputChange, style: { display: 'none' } }), jsxRuntime.jsx("div", { ...getDropzoneProps(), onDrop: handleDrop, children: children(renderProps) })] }));
    }
    // Modern default UI
    return (jsxRuntime.jsxs("div", { className: `modern-file-uploader ${className}`, style: style, children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", accept: accept, multiple: multiple, onChange: handleFileInputChange, style: { display: 'none' } }), showPreview && selectedFiles.length > 0 && (jsxRuntime.jsxs("div", { className: "file-previews", style: { marginBottom: '20px' }, children: [jsxRuntime.jsx("div", { style: {
                            display: 'grid',
                            gridTemplateColumns: 'repeat(auto-fill, minmax(120px, 1fr))',
                            gap: '12px',
                            padding: '16px',
                            backgroundColor: '#f8f9fa',
                            borderRadius: '12px',
                            border: '1px solid #e9ecef'
                        }, children: selectedFiles.map((file, index) => (jsxRuntime.jsxs("div", { className: "file-preview-card", style: {
                                position: 'relative',
                                backgroundColor: 'white',
                                borderRadius: '8px',
                                padding: '8px',
                                boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
                                transition: 'transform 0.2s ease, box-shadow 0.2s ease'
                            }, children: [jsxRuntime.jsx("div", { style: {
                                        width: '100%',
                                        height: '80px',
                                        backgroundColor: '#f8f9fa',
                                        borderRadius: '6px',
                                        display: 'flex',
                                        alignItems: 'center',
                                        justifyContent: 'center',
                                        marginBottom: '8px',
                                        overflow: 'hidden'
                                    }, children: previewUrls[index] ? (jsxRuntime.jsx("img", { src: previewUrls[index], alt: `Preview ${index + 1}`, style: {
                                            width: '100%',
                                            height: '100%',
                                            objectFit: 'cover',
                                            borderRadius: '4px'
                                        } })) : (jsxRuntime.jsx("div", { style: {
                                            fontSize: '24px',
                                            color: '#6c757d'
                                        }, children: getFileIcon(file.type) })) }), jsxRuntime.jsxs("div", { style: {
                                        fontSize: '11px',
                                        color: '#495057',
                                        textAlign: 'center',
                                        lineHeight: '1.2'
                                    }, children: [jsxRuntime.jsx("div", { style: {
                                                fontWeight: '500',
                                                marginBottom: '2px',
                                                overflow: 'hidden',
                                                textOverflow: 'ellipsis',
                                                whiteSpace: 'nowrap'
                                            }, children: file.name }), jsxRuntime.jsx("div", { style: { color: '#6c757d' }, children: formatFileSize$1(file.size) })] }), jsxRuntime.jsx("button", { onClick: () => removeFile(index), style: {
                                        position: 'absolute',
                                        top: '4px',
                                        right: '4px',
                                        backgroundColor: '#dc3545',
                                        color: 'white',
                                        border: 'none',
                                        borderRadius: '50%',
                                        width: '20px',
                                        height: '20px',
                                        cursor: 'pointer',
                                        fontSize: '12px',
                                        display: 'flex',
                                        alignItems: 'center',
                                        justifyContent: 'center',
                                        boxShadow: '0 1px 3px rgba(0,0,0,0.2)',
                                        transition: 'background-color 0.2s ease'
                                    }, onMouseEnter: (e) => e.currentTarget.style.backgroundColor = '#c82333', onMouseLeave: (e) => e.currentTarget.style.backgroundColor = '#dc3545', children: "\u00D7" })] }, index))) }), jsxRuntime.jsxs("div", { style: {
                            display: 'flex',
                            gap: '12px',
                            justifyContent: 'center',
                            marginTop: '16px'
                        }, children: [jsxRuntime.jsx("button", { onClick: () => upload(), disabled: state.isUploading || selectedFiles.length === 0, style: {
                                    padding: '12px 24px',
                                    backgroundColor: state.isUploading ? '#6c757d' : '#007bff',
                                    color: 'white',
                                    border: 'none',
                                    borderRadius: '8px',
                                    cursor: state.isUploading ? 'not-allowed' : 'pointer',
                                    fontSize: '14px',
                                    fontWeight: '500',
                                    transition: 'background-color 0.2s ease',
                                    boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
                                }, children: state.isUploading ? 'Uploading...' : `Upload ${selectedFiles.length} File${selectedFiles.length > 1 ? 's' : ''}` }), jsxRuntime.jsx("button", { onClick: clearFiles, disabled: state.isUploading, style: {
                                    padding: '12px 24px',
                                    backgroundColor: 'transparent',
                                    color: '#6c757d',
                                    border: '1px solid #dee2e6',
                                    borderRadius: '8px',
                                    cursor: state.isUploading ? 'not-allowed' : 'pointer',
                                    fontSize: '14px',
                                    fontWeight: '500',
                                    transition: 'all 0.2s ease'
                                }, children: "Clear All" })] })] })), state.isUploading && (jsxRuntime.jsxs("div", { style: {
                    backgroundColor: '#f8f9fa',
                    borderRadius: '12px',
                    padding: '20px',
                    marginBottom: '20px',
                    border: '1px solid #e9ecef'
                }, children: [jsxRuntime.jsxs("div", { style: {
                            display: 'flex',
                            alignItems: 'center',
                            justifyContent: 'space-between',
                            marginBottom: '12px'
                        }, children: [jsxRuntime.jsx("span", { style: { fontSize: '14px', fontWeight: '500', color: '#495057' }, children: "Uploading files..." }), jsxRuntime.jsxs("span", { style: { fontSize: '14px', color: '#6c757d' }, children: [state.progress.progress, "%"] })] }), jsxRuntime.jsx("div", { style: {
                            width: '100%',
                            height: '8px',
                            backgroundColor: '#e9ecef',
                            borderRadius: '4px',
                            overflow: 'hidden',
                            marginBottom: '12px'
                        }, children: jsxRuntime.jsx("div", { style: {
                                width: `${state.progress.progress}%`,
                                height: '100%',
                                backgroundColor: '#007bff',
                                borderRadius: '4px',
                                transition: 'width 0.3s ease'
                            } }) }), jsxRuntime.jsx("button", { onClick: cancel, style: {
                            padding: '8px 16px',
                            backgroundColor: '#dc3545',
                            color: 'white',
                            border: 'none',
                            borderRadius: '6px',
                            cursor: 'pointer',
                            fontSize: '12px',
                            fontWeight: '500'
                        }, children: "Cancel Upload" })] })), state.error && (jsxRuntime.jsxs("div", { style: {
                    backgroundColor: '#f8d7da',
                    color: '#721c24',
                    borderRadius: '12px',
                    padding: '20px',
                    marginBottom: '20px',
                    border: '1px solid #f5c6cb',
                    textAlign: 'center'
                }, children: [jsxRuntime.jsx("div", { style: { fontSize: '32px', marginBottom: '12px' }, children: "\u26A0\uFE0F" }), jsxRuntime.jsxs("p", { style: { margin: '0 0 12px 0', fontSize: '14px', fontWeight: '500' }, children: ["Upload failed: ", state.error.message] }), jsxRuntime.jsx("button", { onClick: resetAll, style: {
                            padding: '8px 16px',
                            backgroundColor: '#007bff',
                            color: 'white',
                            border: 'none',
                            borderRadius: '6px',
                            cursor: 'pointer',
                            fontSize: '12px',
                            fontWeight: '500'
                        }, children: "Try Again" })] })), state.result && (jsxRuntime.jsxs("div", { style: {
                    backgroundColor: '#d4edda',
                    color: '#155724',
                    borderRadius: '12px',
                    padding: '20px',
                    marginBottom: '20px',
                    border: '1px solid #c3e6cb',
                    textAlign: 'center'
                }, children: [jsxRuntime.jsx("div", { style: { fontSize: '32px', marginBottom: '12px' }, children: "\u2705" }), jsxRuntime.jsx("p", { style: { margin: '0 0 12px 0', fontSize: '14px', fontWeight: '500' }, children: "Upload completed successfully!" }), jsxRuntime.jsx("button", { onClick: resetAll, style: {
                            padding: '8px 16px',
                            backgroundColor: '#007bff',
                            color: 'white',
                            border: 'none',
                            borderRadius: '6px',
                            cursor: 'pointer',
                            fontSize: '12px',
                            fontWeight: '500'
                        }, children: "Upload More Files" })] })), jsxRuntime.jsx("div", { ...getDropzoneProps(), onDrop: handleDrop, onClick: openFilePicker, style: {
                    border: `2px dashed ${isDragActive ? '#007bff' : '#dee2e6'}`,
                    borderRadius: '12px',
                    padding: '40px 20px',
                    textAlign: 'center',
                    cursor: 'pointer',
                    transition: 'all 0.3s ease',
                    backgroundColor: isDragActive ? '#f0f8ff' : '#fafbfc',
                    position: 'relative',
                    ...style
                }, children: jsxRuntime.jsxs("div", { style: {
                        display: 'flex',
                        flexDirection: 'column',
                        alignItems: 'center',
                        gap: '12px'
                    }, children: [jsxRuntime.jsx("div", { style: {
                                fontSize: '48px',
                                color: isDragActive ? '#007bff' : '#6c757d',
                                transition: 'color 0.3s ease'
                            }, children: isDragActive ? '📂' : '📁' }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("p", { style: {
                                        margin: '0 0 8px 0',
                                        fontSize: '18px',
                                        fontWeight: '600',
                                        color: '#495057'
                                    }, children: isDragActive ? 'Drop files here' : 'Choose files or drag and drop' }), jsxRuntime.jsxs("p", { style: {
                                        margin: '0 0 4px 0',
                                        fontSize: '14px',
                                        color: '#6c757d'
                                    }, children: [multiple ? 'Select multiple files' : 'Select a file', accept && ` (${accept.replace(/,/g, ', ')})`] }), jsxRuntime.jsxs("p", { style: {
                                        margin: '0',
                                        fontSize: '12px',
                                        color: '#adb5bd'
                                    }, children: ["Maximum file size: ", formatFileSize$1(config.maxFileSize || 50 * 1024 * 1024)] })] })] }) })] }));
};
// Utility functions
function getFileIcon(mimeType) {
    if (mimeType.startsWith('image/'))
        return '🖼️';
    if (mimeType.startsWith('video/'))
        return '🎥';
    if (mimeType.startsWith('audio/'))
        return '🎵';
    if (mimeType.includes('pdf'))
        return '📄';
    if (mimeType.includes('word') || mimeType.includes('document'))
        return '📝';
    if (mimeType.includes('excel') || mimeType.includes('spreadsheet'))
        return '📊';
    if (mimeType.includes('powerpoint') || mimeType.includes('presentation'))
        return '📈';
    if (mimeType.includes('zip') || mimeType.includes('archive'))
        return '📦';
    return '📄';
}
function formatFileSize$1(bytes) {
    if (bytes === 0)
        return '0 Bytes';
    const k = 1024;
    const sizes = ['Bytes', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}

const ImageUploader = ({ config, options, showPreview = true, previewSize = { width: 200, height: 200 }, multiple = false, autoUpload = true, className = '', style, onSuccess, onError, onProgress }) => {
    const [previewUrls, setPreviewUrls] = React.useState([]);
    const [selectedFiles, setSelectedFiles] = React.useState([]);
    // Clean up preview URLs when component unmounts
    React.useEffect(() => {
        return () => {
            previewUrls.forEach(url => URL.revokeObjectURL(url));
        };
    }, [previewUrls]);
    const handleSuccess = (result) => {
        // Clear previews on successful upload
        if (showPreview) {
            previewUrls.forEach(url => URL.revokeObjectURL(url));
            setPreviewUrls([]);
            setSelectedFiles([]);
        }
        onSuccess?.(result);
    };
    const handleReset = () => {
        if (showPreview) {
            previewUrls.forEach(url => URL.revokeObjectURL(url));
            setPreviewUrls([]);
            setSelectedFiles([]);
        }
    };
    const imageOptions = {
        category: 'medical_image',
        ...options
    };
    return (jsxRuntime.jsx("div", { className: `image-uploader ${className}`, style: style, children: jsxRuntime.jsx(FileUploader, { config: config, options: imageOptions, multiple: multiple, accept: "image/*", autoUpload: autoUpload, onSuccess: handleSuccess, onError: onError, onProgress: onProgress, children: ({ isUploading, progress, result, error, isDragActive, openFilePicker, upload, cancel, reset }) => (jsxRuntime.jsxs("div", { children: [showPreview && previewUrls.length > 0 && (jsxRuntime.jsxs("div", { className: "image-previews", style: { marginBottom: '20px' }, children: [jsxRuntime.jsx("div", { style: {
                                    display: 'flex',
                                    flexWrap: 'wrap',
                                    gap: '10px',
                                    justifyContent: 'center'
                                }, children: previewUrls.map((url, index) => (jsxRuntime.jsxs("div", { className: "image-preview", style: {
                                        position: 'relative',
                                        border: '2px solid #ddd',
                                        borderRadius: '8px',
                                        overflow: 'hidden'
                                    }, children: [jsxRuntime.jsx("img", { src: url, alt: `Preview ${index + 1}`, style: {
                                                width: previewSize.width,
                                                height: previewSize.height,
                                                objectFit: 'cover',
                                                display: 'block'
                                            } }), jsxRuntime.jsx("div", { style: {
                                                position: 'absolute',
                                                bottom: '0',
                                                left: '0',
                                                right: '0',
                                                backgroundColor: 'rgba(0,0,0,0.7)',
                                                color: 'white',
                                                padding: '5px',
                                                fontSize: '12px',
                                                textAlign: 'center'
                                            }, children: selectedFiles[index]?.name }), jsxRuntime.jsx("button", { onClick: (e) => {
                                                e.stopPropagation();
                                                const newUrls = [...previewUrls];
                                                const newFiles = [...selectedFiles];
                                                URL.revokeObjectURL(newUrls[index]);
                                                newUrls.splice(index, 1);
                                                newFiles.splice(index, 1);
                                                setPreviewUrls(newUrls);
                                                setSelectedFiles(newFiles);
                                            }, style: {
                                                position: 'absolute',
                                                top: '5px',
                                                right: '5px',
                                                backgroundColor: 'rgba(255,0,0,0.8)',
                                                color: 'white',
                                                border: 'none',
                                                borderRadius: '50%',
                                                width: '24px',
                                                height: '24px',
                                                cursor: 'pointer',
                                                fontSize: '14px',
                                                display: 'flex',
                                                alignItems: 'center',
                                                justifyContent: 'center'
                                            }, children: "\u00D7" })] }, index))) }), !autoUpload && selectedFiles.length > 0 && !isUploading && (jsxRuntime.jsxs("div", { style: { textAlign: 'center', marginTop: '15px' }, children: [jsxRuntime.jsxs("button", { onClick: () => upload(selectedFiles), style: {
                                            padding: '10px 20px',
                                            backgroundColor: '#007bff',
                                            color: 'white',
                                            border: 'none',
                                            borderRadius: '5px',
                                            cursor: 'pointer',
                                            fontSize: '16px',
                                            marginRight: '10px'
                                        }, children: ["Upload ", selectedFiles.length, " Image", selectedFiles.length > 1 ? 's' : ''] }), jsxRuntime.jsx("button", { onClick: handleReset, style: {
                                            padding: '10px 20px',
                                            backgroundColor: '#6c757d',
                                            color: 'white',
                                            border: 'none',
                                            borderRadius: '5px',
                                            cursor: 'pointer',
                                            fontSize: '16px'
                                        }, children: "Clear" })] }))] })), jsxRuntime.jsx("div", { style: {
                            border: '2px dashed #ccc',
                            borderRadius: '8px',
                            padding: '30px',
                            textAlign: 'center',
                            cursor: 'pointer',
                            transition: 'all 0.3s ease',
                            backgroundColor: isDragActive ? '#f0f8ff' : '#fafafa',
                            borderColor: isDragActive ? '#007bff' : '#ccc'
                        }, onClick: () => {
                            if (!isUploading) {
                                openFilePicker();
                            }
                        }, children: isUploading ? (jsxRuntime.jsxs("div", { className: "upload-progress", children: [jsxRuntime.jsx("div", { style: {
                                        width: '100%',
                                        height: '8px',
                                        backgroundColor: '#e0e0e0',
                                        borderRadius: '4px',
                                        overflow: 'hidden',
                                        marginBottom: '15px'
                                    }, children: jsxRuntime.jsx("div", { style: {
                                            width: `${progress}%`,
                                            height: '100%',
                                            backgroundColor: '#007bff',
                                            transition: 'width 0.3s ease'
                                        } }) }), jsxRuntime.jsxs("p", { style: { margin: '10px 0', fontSize: '16px' }, children: ["Uploading images... ", progress, "%"] }), jsxRuntime.jsx("button", { onClick: (e) => {
                                        e.stopPropagation();
                                        cancel();
                                    }, style: {
                                        padding: '8px 16px',
                                        backgroundColor: '#dc3545',
                                        color: 'white',
                                        border: 'none',
                                        borderRadius: '4px',
                                        cursor: 'pointer'
                                    }, children: "Cancel Upload" })] })) : error ? (jsxRuntime.jsxs("div", { style: { color: '#dc3545' }, children: [jsxRuntime.jsx("div", { style: { fontSize: '48px', marginBottom: '10px' }, children: "\u274C" }), jsxRuntime.jsxs("p", { style: { margin: '10px 0', fontSize: '16px' }, children: ["Upload failed: ", error.message] }), jsxRuntime.jsx("button", { onClick: (e) => {
                                        e.stopPropagation();
                                        reset();
                                        handleReset();
                                    }, style: {
                                        padding: '8px 16px',
                                        backgroundColor: '#007bff',
                                        color: 'white',
                                        border: 'none',
                                        borderRadius: '4px',
                                        cursor: 'pointer'
                                    }, children: "Try Again" })] })) : result ? (jsxRuntime.jsxs("div", { style: { color: '#28a745' }, children: [jsxRuntime.jsx("div", { style: { fontSize: '48px', marginBottom: '10px' }, children: "\u2705" }), jsxRuntime.jsxs("p", { style: { margin: '10px 0', fontSize: '16px', fontWeight: 'bold' }, children: ["Image", Array.isArray(result) ? 's' : '', " uploaded successfully!"] }), result && !Array.isArray(result) && result.thumbnailUrl && (jsxRuntime.jsx("img", { src: result.thumbnailUrl, alt: "Uploaded thumbnail", style: {
                                        maxWidth: '150px',
                                        maxHeight: '150px',
                                        margin: '10px auto',
                                        display: 'block',
                                        borderRadius: '8px',
                                        border: '2px solid #28a745'
                                    } })), jsxRuntime.jsx("button", { onClick: (e) => {
                                        e.stopPropagation();
                                        reset();
                                        handleReset();
                                    }, style: {
                                        padding: '8px 16px',
                                        backgroundColor: '#007bff',
                                        color: 'white',
                                        border: 'none',
                                        borderRadius: '4px',
                                        cursor: 'pointer',
                                        marginTop: '10px'
                                    }, children: "Upload Another" })] })) : (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("div", { style: { fontSize: '48px', marginBottom: '15px' }, children: "\uD83D\uDDBC\uFE0F" }), jsxRuntime.jsx("p", { style: { margin: '10px 0', fontSize: '18px', fontWeight: 'bold' }, children: isDragActive ? 'Drop images here' : 'Click to upload images or drag and drop' }), jsxRuntime.jsx("p", { style: { margin: '5px 0', fontSize: '14px', color: '#666' }, children: multiple ? 'Select multiple images' : 'Select an image' }), jsxRuntime.jsx("p", { style: { margin: '5px 0', fontSize: '12px', color: '#999' }, children: "Supported formats: JPEG, PNG, GIF, WebP" }), jsxRuntime.jsxs("p", { style: { margin: '5px 0', fontSize: '12px', color: '#999' }, children: ["Max size: ", formatFileSize(config.maxFileSize || 50 * 1024 * 1024)] })] })) })] })) }) }));
};
// Utility function to format file size
function formatFileSize(bytes) {
    if (bytes === 0)
        return '0 Bytes';
    const k = 1024;
    const sizes = ['Bytes', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}

/**
 * Health Ecosystem File Upload Library
 * Version 3.0 - Filestack-like Widget with Multi-source Picker
 */
// React compatibility layer
// Utility functions
const createFileUploadConfig = (baseUrl, authToken, options) => {
    const defaultAllowedTypes = [
        'image/jpeg', 'image/png', 'image/gif', 'image/webp',
        'application/pdf', 'application/msword',
        'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
        'text/plain', 'text/csv', 'video/mp4', 'video/webm'
    ];
    return {
        baseUrl,
        authToken: authToken || '',
        maxFileSize: options?.maxFileSize || 50 * 1024 * 1024, // 50MB
        allowedTypes: options?.allowedTypes || defaultAllowedTypes,
        timeout: options?.timeout || 30000,
        enableRetry: options?.enableRetry ?? true,
        maxRetries: options?.maxRetries || 3
    };
};
const createUploadOptions = (category, options) => ({
    category,
    isPublic: true, // Default to public for widget
    ...options
});
// Library initialization helper (NEW)
const initializeFileUploadLibrary = (serverEndpoint, accessToken, options) => {
    const configOptions = {};
    if (options?.maxFileSize !== undefined) {
        configOptions.maxFileSize = options.maxFileSize;
    }
    if (options?.allowedTypes !== undefined) {
        configOptions.allowedTypes = options.allowedTypes;
    }
    const config = createFileUploadConfig(serverEndpoint, accessToken, configOptions);
    const uploadOptions = createUploadOptions(options?.category || 'other', {
        isPublic: options?.isPublic ?? true
    });
    return {
        config,
        uploadOptions
    };
};
// Widget initialization helper
const initializeFileUploadWidget = (baseUrl, authToken, options) => {
    const configOptions = {};
    if (options?.maxFileSize !== undefined) {
        configOptions.maxFileSize = options.maxFileSize;
    }
    if (options?.allowedTypes !== undefined) {
        configOptions.allowedTypes = options.allowedTypes;
    }
    const config = createFileUploadConfig(baseUrl, authToken, configOptions);
    return {
        config,
        defaultOptions: {
            multiple: options?.multiple ?? true,
            showLibrary: options?.showLibrary ?? true
        }
    };
};
// Constants
const FILE_CATEGORIES = {
    MEDICAL_IMAGE: 'medical_image',
    DOCUMENT: 'document',
    REPORT: 'report',
    PRESCRIPTION: 'prescription',
    LAB_RESULT: 'lab_result',
    PROFILE_PICTURE: 'profile_picture',
    IDENTIFICATION: 'identification',
    INSURANCE: 'insurance',
    VIDEO: 'video',
    AUDIO: 'audio',
    OTHER: 'other'
};
const ENTITY_TYPES = {
    PATIENT: 'patient',
    DOCTOR: 'doctor',
    APPOINTMENT: 'appointment',
    CONSULTATION: 'consultation',
    PRESCRIPTION: 'prescription',
    BUSINESS: 'business',
    USER: 'user',
    OTHER: 'other'
};
const MAX_FILE_SIZES = {
    IMAGE: 10 * 1024 * 1024, // 10MB
    DOCUMENT: 50 * 1024 * 1024, // 50MB
    VIDEO: 100 * 1024 * 1024, // 100MB
    AUDIO: 25 * 1024 * 1024 // 25MB
};
// Upload sources for widget
const UPLOAD_SOURCES = {
    DEVICE: 'device',
    CAMERA: 'camera',
    GOOGLE_DRIVE: 'googledrive',
    DROPBOX: 'dropbox',
    ONEDRIVE: 'onedrive',
    URL: 'url',
    INSTAGRAM: 'instagram',
    FACEBOOK: 'facebook'
};
// Version
const VERSION = '1.0.4';

exports.ENTITY_TYPES = ENTITY_TYPES;
exports.FILE_CATEGORIES = FILE_CATEGORIES;
exports.FileUploadButton = FileUploadButton;
exports.FileUploadClient = FileUploadClient;
exports.FileUploadLibrary = FileUploadLibrary;
exports.FileUploadModal = FileUploadModal;
exports.FileUploadTrigger = FileUploadTrigger;
exports.FileUploadWidget = FileUploadWidget;
exports.FileUploader = FileUploader;
exports.ImageUploader = ImageUploader;
exports.MAX_FILE_SIZES = MAX_FILE_SIZES;
exports.REACT_COMPAT_INFO = REACT_COMPAT_INFO;
exports.UPLOAD_SOURCES = UPLOAD_SOURCES;
exports.VERSION = VERSION;
exports.createFileUploadConfig = createFileUploadConfig;
exports.createUploadOptions = createUploadOptions;
exports.initializeFileUploadLibrary = initializeFileUploadLibrary;
exports.initializeFileUploadWidget = initializeFileUploadWidget;
exports.useDropzone = useDropzone;
exports.useFileUpload = useFileUpload;
//# sourceMappingURL=index.js.map