@autorender/sdk-core 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/constants/defaults.ts","../src/client/api-client.ts","../src/utils/helpers.ts","../src/core/uploader-controller.ts","../src/widget/styles.ts","../src/widget/uploader-element.ts"],"sourcesContent":["import { AutorenderApiClient } from './client/api-client';\nimport { UploaderController } from './core/uploader-controller';\nimport type { ControllerOptions } from './core/uploader-controller';\nimport { DEFAULT_THEME, DEFAULT_SOURCES } from './constants/defaults';\nimport type {\n CreateUploaderOptions,\n UploaderInstance,\n ThemeOptions,\n UploadSourceOption,\n} from './types';\nimport { AutorenderUploaderElement } from './widget/uploader-element';\n\ntype ThemeName = 'light' | 'dark' | 'system';\n\nconst SOURCE_ALIAS_MAP: Record<string, string> = {\n local: 'device',\n device: 'device',\n fromdevice: 'device',\n camera: 'camera',\n facebook: 'facebook',\n fb: 'facebook',\n insta: 'facebook',\n instagram: 'facebook',\n gdrive: 'google-drive',\n googledrive: 'google-drive',\n google: 'google-drive',\n googledisk: 'google-drive',\n 'google-drive': 'google-drive',\n};\n\nfunction ensureCustomElement() {\n if (!customElements.get(AutorenderUploaderElement.tagName)) {\n customElements.define(AutorenderUploaderElement.tagName, AutorenderUploaderElement);\n }\n}\n\nfunction resolveTarget(target: string | HTMLElement): HTMLElement {\n if (typeof target === 'string') {\n const element = document.querySelector<HTMLElement>(target);\n if (!element) {\n throw new Error(`Target element \"${target}\" not found`);\n }\n return element;\n }\n return target;\n}\n\nfunction resolveThemePreset(theme?: ThemeName): ThemeOptions {\n const base = {\n borderRadius: DEFAULT_THEME.borderRadius,\n dropzoneBackground: DEFAULT_THEME.dropzoneBackground,\n dropzoneBorder: DEFAULT_THEME.dropzoneBorder,\n };\n\n switch (theme) {\n case 'dark':\n return {\n appearance: 'dark',\n accentColor: '#4C8DFF',\n ...base,\n };\n case 'system':\n return {\n appearance: 'system',\n accentColor: DEFAULT_THEME.accentColor,\n ...base,\n };\n default:\n return {\n appearance: 'light',\n accentColor: DEFAULT_THEME.accentColor,\n ...base,\n };\n }\n}\n\nfunction resolveSourcesConfig(input?: string | string[]): UploadSourceOption[] {\n if (input === undefined || input === null) {\n return [];\n }\n\n const provided = Array.isArray(input)\n ? input\n : input\n .split(',')\n .map(entry => entry.trim())\n .filter(Boolean);\n\n if (provided.length === 0) {\n return [];\n }\n\n const resolved: UploadSourceOption[] = [];\n const seen = new Set<string>();\n\n for (const entry of provided) {\n const normalized = entry.toLowerCase().replace(/[\\s_-]+/g, '');\n const mappedId = SOURCE_ALIAS_MAP[normalized] ?? normalized;\n if (seen.has(mappedId)) continue;\n const match = DEFAULT_SOURCES.find(option => option.id === mappedId);\n if (match) {\n resolved.push(match);\n seen.add(mappedId);\n }\n }\n\n return resolved;\n}\n\nfunction normalizeOptions(\n options: Partial<CreateUploaderOptions>,\n applyDefaults = false\n): Partial<ControllerOptions> {\n const {\n type,\n theme,\n sources,\n classNames,\n labels,\n fileLayout,\n showGridFileName,\n apiKey: _apiKey,\n target: _target,\n ...rest\n } = options;\n\n const normalized: any = { ...rest };\n\n if (type !== undefined) {\n normalized.type = type === 'button' ? 'button' : 'inline';\n } else if (applyDefaults) {\n normalized.type = 'inline';\n }\n\n if (theme !== undefined) {\n normalized.theme = resolveThemePreset(theme);\n } else if (applyDefaults) {\n normalized.theme = resolveThemePreset('light');\n }\n\n if (sources !== undefined) {\n normalized.sources = resolveSourcesConfig(sources);\n } else if ('sources' in options) {\n // Explicitly undefined - means no sources (all disabled)\n normalized.sources = [];\n } else if (applyDefaults) {\n normalized.sources = [];\n }\n\n if (classNames !== undefined) {\n normalized.classNames = classNames;\n }\n\n if (labels !== undefined) {\n normalized.labels = labels;\n }\n\n if (fileLayout !== undefined) {\n normalized.fileLayout = fileLayout;\n } else if (applyDefaults) {\n normalized.fileLayout = 'list';\n }\n\n if (showGridFileName !== undefined) {\n normalized.showGridFileName = showGridFileName;\n } else if (applyDefaults) {\n normalized.showGridFileName = true;\n }\n\n return normalized;\n}\n\nexport function createUploader(options: CreateUploaderOptions): UploaderInstance {\n const target = resolveTarget(options.target);\n ensureCustomElement();\n\n const widget = document.createElement(\n AutorenderUploaderElement.tagName\n ) as AutorenderUploaderElement;\n\n // Clear target and mount widget\n target.innerHTML = '';\n target.appendChild(widget);\n\n const client = new AutorenderApiClient({\n apiKey: options.apiKey,\n });\n\n const controllerOptions = normalizeOptions(options, true) as ControllerOptions;\n\n const controller = new UploaderController(\n client,\n widget,\n controllerOptions\n );\n\n widget.setController(controller, controllerOptions);\n\n return {\n openFileDialog: () => widget.openFileDialog(),\n startUpload: () => controller.uploadAll(),\n reset: () => controller.reset(),\n destroy: () => {\n controller.cancel();\n controller.reset();\n widget.remove();\n },\n updateOptions: (partialOptions: Partial<CreateUploaderOptions>) => {\n const normalized = normalizeOptions(partialOptions, false);\n controller.setOptions(normalized);\n widget.updateOptions(normalized);\n },\n getState: () => controller.getState(),\n };\n}\n\nexport * from './types';\nexport function registerAutorenderUploaderElement() {\n ensureCustomElement();\n}\n\n","import type { IconSet, LabelSet, ThemeOptions, UploadSourceOption } from '../types';\n\nexport const DEFAULT_BASE_URL = 'https://autorenderv3.vercel.app/api/public';\n// export const DEFAULT_BASE_URL = 'http://localhost:3000/api/public';\n\n\nexport const DEFAULT_LABELS: Required<LabelSet> = {\n title: 'Upload files',\n description: 'Drag & drop files or click to browse.',\n selectButton: 'Upload files',\n selectFolderButton: 'Upload folder',\n uploadButton: 'Upload',\n uploading: 'Uploading...',\n uploadComplete: 'All files uploaded successfully.',\n uploadFailed: 'Unable to upload files. Please try again.',\n retry: 'Retry',\n remove: 'Remove',\n addMore: 'Add more',\n done: 'Done',\n clear: 'Clear',\n cancel: 'Cancel',\n dropzoneTitle: 'Drop files here',\n duplicateFileExists: 'The following file already exists in this folder:',\n duplicateFilesExist: 'The following files already exist in this folder:',\n duplicateFileError: 'File already exists in this folder.',\n invalidApiKey: 'Invalid API key. Please verify your credentials and try again.',\n};\n\nexport const DEFAULT_ICONS: Required<IconSet> = {\n upload: `\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path d=\"M12 16a1 1 0 0 1-1-1V7.41l-2.3 2.3a1 1 0 1 1-1.4-1.42l4-4a1 1 0 0 1 1.4 0l4 4a1 1 0 1 1-1.4 1.42L13 7.41V15a1 1 0 0 1-1 1Z\" />\n <path d=\"M5 20a3 3 0 0 1-3-3v-1a1 1 0 0 1 2 0v1a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-1a1 1 0 1 1 2 0v1a3 3 0 0 1-3 3Z\" />\n </svg>\n `,\n success: `\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M9.5 17a1 1 0 0 1-.7-.29l-3.5-3.5a1 1 0 1 1 1.4-1.42l2.8 2.79 7.1-7.09a1 1 0 0 1 1.4 1.42l-7.8 7.79a1 1 0 0 1-.7.3Z\" fill=\"currentColor\" />\n </svg>\n `,\n error: `\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" >\n <path d=\"m12 13.41 3.29 3.3a1 1 0 0 0 1.42-1.42L13.41 12l3.3-3.29a1 1 0 0 0-1.42-1.42L12 10.59l-3.29-3.3a1 1 0 1 0-1.42 1.42L10.59 12l-3.3 3.29a1 1 0 0 0 1.42 1.42L12 13.41Z\" />\n </svg>\n `,\n remove: `\n <svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M9 5.25C9 4.55964 9.55964 4 10.25 4H13.75C14.4404 4 15 4.55964 15 5.25V7H9V5.25Z\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n />\n <path\n d=\"M5 7H19\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n <rect\n x=\"6.5\"\n y=\"7\"\n width=\"11\"\n height=\"12.5\"\n rx=\"2\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n />\n <path\n d=\"M10 11.5V16\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M14 11.5V16\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n `,\n close: `\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path d=\"M13.41 12 18 7.41 16.59 6 12 10.59 7.41 6 6 7.41 10.59 12 6 16.59 7.41 18 12 13.41 16.59 18 18 16.59 13.41 12Z\" />\n </svg>\n `,\n};\n\nexport const DEFAULT_SOURCES: UploadSourceOption[] = [\n {\n id: 'device',\n label: 'From device',\n kind: 'device',\n icon: `\n <svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" aria-hidden=\"true\">\n <rect x=\"4\" y=\"5\" width=\"16\" height=\"14\" rx=\"2\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M9.5 4h5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n `,\n },\n {\n id: 'camera',\n label: 'Camera',\n kind: 'camera',\n icon: `\n <svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M5 7h2l1-2h8l1 2h2a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linejoin=\"round\" />\n <circle cx=\"12\" cy=\"13\" r=\"3.25\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n </svg>\n `,\n },\n {\n id: 'facebook',\n label: 'Facebook',\n kind: 'facebook',\n icon: `\n <svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"9\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M13 8h2V6h-2a3 3 0 0 0-3 3v1H8v2h2v6h2v-6h2v-2h-2V9a1 1 0 0 1 1-1Z\" fill=\"currentColor\" />\n </svg>\n `,\n },\n {\n id: 'google-drive',\n label: 'Google Drive',\n kind: 'google-drive',\n icon: `\n <svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M6.5 18.5h11l3-5-5-8h-6l-5 8 2 3\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linejoin=\"round\" />\n <path d=\"M8 13.5h8\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n `,\n },\n];\n\nexport const DEFAULT_THEME: Required<\n Pick<ThemeOptions, 'appearance' | 'accentColor' | 'borderRadius' | 'dropzoneBackground' | 'dropzoneBorder'>\n> = {\n appearance: 'light',\n accentColor: '#0C55F9',\n borderRadius: 8,\n dropzoneBackground: 'var(--ar-color-muted)',\n dropzoneBorder: 'var(--ar-color-border)',\n};\n\n","import { DEFAULT_BASE_URL } from '../constants/defaults';\nimport type {\n ApiFolderRequest,\n CompleteUploadPayload,\n CompleteUploadResponse,\n UploadInitRequest,\n UploadInitResponse,\n CompleteUploadRequest,\n CompleteUploadResponseNew,\n AppRunnerResponse,\n} from '../types';\n\ninterface RequestOptions {\n method?: 'GET' | 'POST' | 'PATCH';\n body?: unknown;\n signal?: AbortSignal;\n}\n\nexport class AutorenderApiClient {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private authValidated = false;\n\n constructor(opts: { apiKey: string }) {\n if (!opts.apiKey) {\n throw new Error('apiKey is required');\n }\n this.apiKey = opts.apiKey;\n this.baseUrl = DEFAULT_BASE_URL.replace(/\\/+$/, '');\n }\n\n private async request<T>(\n path: string,\n { method = 'POST', body, signal }: RequestOptions = {}\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const response = await fetch(url, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.apiKey,\n },\n body: body ? JSON.stringify(body) : undefined,\n signal,\n });\n\n if (!response.ok) {\n let errorMessage = `Request failed with status ${response.status}`;\n let errorPayload: unknown;\n try {\n const data = await response.json();\n errorPayload = data;\n if (data?.error) {\n errorMessage = data.error;\n } else if (data?.message) {\n errorMessage = data.message;\n }\n } catch {\n // ignore json parse errors\n }\n const error = new Error(errorMessage) as Error & { status?: number; payload?: unknown };\n error.status = response.status;\n error.payload = errorPayload;\n throw error;\n }\n\n if (response.status === 204) {\n return undefined as T;\n }\n\n return (await response.json()) as T;\n }\n\n async validateApiKey(force = false, signal?: AbortSignal): Promise<void> {\n if (this.authValidated && !force) return;\n\n await this.request('/auth/validate', { method: 'GET', signal });\n this.authValidated = true;\n }\n\n // Legacy method - kept for backward compatibility but not used by new upload flow\n completeUpload(\n payload: CompleteUploadPayload,\n signal?: AbortSignal\n ): Promise<CompleteUploadResponse> {\n return this.request<CompleteUploadResponse>('/assets/complete', {\n method: 'POST',\n body: payload,\n signal,\n });\n }\n\n createFolder(payload: ApiFolderRequest, signal?: AbortSignal) {\n return this.request<{ folder_no: string; name: string }>(\n '/assets/folder',\n {\n method: 'POST',\n body: payload,\n signal,\n }\n );\n }\n\n // New upload flow methods\n uploadInit(payload: UploadInitRequest, signal?: AbortSignal): Promise<UploadInitResponse> {\n return this.request<UploadInitResponse>('/assets/upload', {\n method: 'POST',\n body: payload,\n signal,\n });\n }\n\n /**\n * Upload file to App Runner /ingest endpoint\n * This is called directly to App Runner, not through our API\n */\n async ingest(\n file: File,\n uploadToken: string,\n uploadUrl: string,\n onProgress?: (progress: number) => void,\n signal?: AbortSignal\n ): Promise<AppRunnerResponse> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n if (signal) {\n signal.addEventListener('abort', () => {\n xhr.abort();\n reject(new DOMException('Upload aborted', 'AbortError'));\n });\n }\n\n xhr.upload.onprogress = (event) => {\n if (event.lengthComputable && onProgress) {\n const progress = Math.round((event.loaded / event.total) * 100);\n onProgress(progress);\n }\n };\n\n xhr.onerror = () => {\n reject(new Error(`Upload failed: ${xhr.statusText}`));\n };\n\n xhr.onload = () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n const response = JSON.parse(xhr.responseText) as AppRunnerResponse;\n resolve(response);\n } catch (error) {\n reject(new Error('Failed to parse response'));\n }\n } else {\n try {\n const error = JSON.parse(xhr.responseText);\n reject(new Error(error.message || `Upload failed: ${xhr.statusText}`));\n } catch {\n reject(new Error(`Upload failed: ${xhr.statusText}`));\n }\n }\n };\n\n xhr.open('POST', uploadUrl);\n xhr.setRequestHeader('Authorization', `Bearer ${uploadToken}`);\n xhr.setRequestHeader('Content-Type', file.type || 'application/octet-stream');\n xhr.send(file);\n });\n }\n\n completeUploadNew(\n payload: CompleteUploadRequest,\n signal?: AbortSignal\n ): Promise<CompleteUploadResponseNew> {\n return this.request<CompleteUploadResponseNew>('/assets/complete', {\n method: 'POST',\n body: payload,\n signal,\n });\n }\n}\n\nexport {}\n\n","export function generateId(): string {\n if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) {\n return crypto.randomUUID();\n }\n\n return 'id-' + Math.random().toString(36).slice(2, 11);\n}\n\nexport function chunkArray<T>(items: T[], chunkSize: number): T[][] {\n if (chunkSize <= 0) {\n return [items];\n }\n\n const chunks: T[][] = [];\n for (let i = 0; i < items.length; i += chunkSize) {\n chunks.push(items.slice(i, i + chunkSize));\n }\n return chunks;\n}\n\nexport function clamp(value: number, min = 0, max = 1) {\n return Math.min(Math.max(value, min), max);\n}\n\nexport function formatBytes(bytes: number) {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n const num = bytes / Math.pow(k, i);\n return `${num.toFixed(num > 10 ? 0 : 1)} ${sizes[i]}`;\n}\n\nexport function createElement<T extends keyof HTMLElementTagNameMap>(\n tag: T,\n className?: string,\n textContent?: string\n): HTMLElementTagNameMap[T] {\n const element = document.createElement(tag);\n if (className) element.className = className;\n if (textContent) element.textContent = textContent;\n return element;\n}\n\nexport function resolveIcon(renderer: string | HTMLElement | (() => string | HTMLElement)) {\n if (typeof renderer === 'function') {\n return resolveIcon(renderer());\n }\n if (typeof renderer === 'string') {\n const template = document.createElement('template');\n template.innerHTML = renderer.trim();\n return template.content.firstElementChild as HTMLElement | null;\n }\n return renderer ? (renderer.cloneNode(true) as HTMLElement) : null;\n}\n\nexport function toCssVars(theme: {\n appearance?: 'light' | 'dark' | 'system';\n accentColor?: string;\n borderRadius?: number;\n fontFamily?: string;\n dropzoneBackground?: string;\n dropzoneBorder?: string;\n}) {\n const variables: Record<string, string> = {};\n if (theme.accentColor) {\n variables['--ar-accent'] = theme.accentColor;\n }\n if (theme.borderRadius !== undefined) {\n variables['--ar-radius'] = `${theme.borderRadius}px`;\n }\n if (theme.fontFamily) {\n variables['--ar-font-family'] = theme.fontFamily;\n }\n if (theme.dropzoneBackground) {\n variables['--ar-dropzone-bg'] = theme.dropzoneBackground;\n }\n if (theme.dropzoneBorder) {\n variables['--ar-dropzone-border'] = theme.dropzoneBorder;\n }\n return variables;\n}\n\nexport function applyCssVariables(\n element: HTMLElement,\n variables: Record<string, string>\n) {\n Object.entries(variables).forEach(([key, value]) => {\n element.style.setProperty(key, value);\n });\n}\n\nexport function getRelativeFolderPath(\n basePath: string | undefined,\n relativePath: string | undefined\n) {\n if (!relativePath) return undefined;\n\n const parts = relativePath\n .split('/')\n .map(segment => segment.trim())\n .filter(segment => segment && segment !== '.');\n\n if (parts.length <= 1) {\n return undefined;\n }\n\n const folderSegments = parts.slice(0, -1);\n\n if (basePath) {\n const baseSegments = basePath\n .split('/')\n .map(segment => segment.trim())\n .filter(segment => segment && segment !== '.');\n\n let offset = 0;\n while (\n offset < baseSegments.length &&\n offset < folderSegments.length &&\n folderSegments[offset] === baseSegments[offset]\n ) {\n offset += 1;\n }\n\n return offset < folderSegments.length\n ? folderSegments.slice(offset).join('/')\n : undefined;\n }\n\n return folderSegments.length ? folderSegments.join('/') : undefined;\n}\n\nexport function calculateBatchProgress(items: { progress: number }[]) {\n if (items.length === 0) return 0;\n const total = items.reduce((acc, item) => acc + item.progress, 0);\n return Math.round(total / items.length);\n}\n\n","import { AutorenderApiClient } from '../client/api-client';\nimport type {\n CreateUploaderOptions,\n UploadItem,\n UploadedFileResponse,\n ThemeOptions,\n UploadSourceOption,\n UploadInitResponse,\n AppRunnerResponse,\n CompleteUploadResponseNew,\n} from '../types';\nimport {\n applyCssVariables,\n calculateBatchProgress,\n generateId,\n getRelativeFolderPath,\n toCssVars,\n} from '../utils/helpers';\n\nconst DEFAULT_PARALLEL_UPLOADS = 4;\n\ninterface FileSelection {\n file: File;\n relativePath?: string;\n}\n\nexport interface ControllerOptions\n extends Omit<CreateUploaderOptions, 'target' | 'theme' | 'sources'> {\n theme?: ThemeOptions;\n sources?: UploadSourceOption[];\n}\n\nexport interface ControllerState {\n items: UploadItem[];\n isUploading: boolean;\n progress: number;\n duplicates: string[];\n}\n\ntype ControllerEvents =\n | 'statechange'\n | 'progress'\n | 'fileprogress'\n | 'error'\n | 'complete'\n | 'filesadded';\n\nexport class UploaderController extends EventTarget {\n private options: ControllerOptions;\n private readonly client: AutorenderApiClient;\n private items: UploadItem[] = [];\n private abortController: AbortController | null = null;\n private isUploading = false;\n private targetElement: HTMLElement;\n private duplicateConflicts = new Set<string>();\n\n private isAbortError(error: unknown): boolean {\n if (!error) return false;\n if (error instanceof DOMException && error.name === 'AbortError') return true;\n if (error instanceof Error && error.name === 'AbortError') return true;\n const message =\n error instanceof Error\n ? error.message\n : typeof error === 'string'\n ? error\n : '';\n return typeof message === 'string' && message.toLowerCase().includes('abort');\n }\n\n constructor(\n client: AutorenderApiClient,\n target: HTMLElement,\n options: ControllerOptions\n ) {\n super();\n this.client = client;\n this.targetElement = target;\n this.options = options;\n this.applyTheme();\n }\n\n setOptions(options: Partial<ControllerOptions>) {\n this.options = {\n ...this.options,\n ...options,\n };\n this.applyTheme();\n this.dispatch('statechange');\n }\n\n getOptions(): ControllerOptions {\n return this.options;\n }\n\n getState(): ControllerState {\n return {\n items: this.items,\n isUploading: this.isUploading,\n progress: calculateBatchProgress(this.items),\n duplicates: Array.from(this.duplicateConflicts),\n };\n }\n\n addFiles(files: FileSelection[]) {\n const existingKeys = new Map<string, UploadItem>();\n const basePathKey = this.normalizePath(this.options.folderPath) ?? '';\n const buildKey = (file: File, folderPath: string, relativePath?: string) =>\n `${basePathKey}::${folderPath ?? ''}::${relativePath ?? ''}::${file.name}::${file.size}`;\n\n this.items.forEach(item => {\n existingKeys.set(buildKey(item.file, item.folderPath, item.relativePath), item);\n });\n\n const newItems = files.map(({ file, relativePath }) => {\n const folderPath = getRelativeFolderPath(\n this.options.folderPath,\n relativePath\n );\n\n const previewUrl = file.type.startsWith('image/')\n ? URL.createObjectURL(file)\n : undefined;\n\n const baseItem: UploadItem = {\n id: generateId(),\n file,\n relativePath,\n folderPath,\n status: 'pending' as const,\n progress: 0,\n previewUrl,\n };\n\n const key = buildKey(file, folderPath, relativePath);\n if (existingKeys.has(key)) {\n baseItem.status = 'completed';\n baseItem.progress = 100;\n baseItem.error = undefined;\n existingKeys.set(key, baseItem);\n return baseItem;\n }\n\n existingKeys.set(key, baseItem);\n return baseItem;\n });\n\n this.items = [...this.items, ...newItems];\n this.dispatch('filesadded', { detail: { items: newItems } });\n\n const duplicates = newItems.filter(item => item.status === 'completed');\n if (duplicates.length) {\n this.markDuplicatesCompleted(duplicates);\n }\n\n this.dispatch('statechange');\n }\n\n removeFile(id: string) {\n const item = this.items.find(entry => entry.id === id);\n if (item?.previewUrl) {\n URL.revokeObjectURL(item.previewUrl);\n }\n this.items = this.items.filter(item => item.id !== id);\n if (item) {\n this.duplicateConflicts.delete(item.file.name);\n }\n this.dispatch('statechange');\n }\n\n reset() {\n this.abortController?.abort();\n this.abortController = null;\n this.isUploading = false;\n this.cleanupPreviews();\n this.items = [];\n this.duplicateConflicts.clear();\n this.dispatch('statechange');\n }\n\n async uploadAll() {\n if (this.isUploading) return;\n if (this.items.length === 0) return;\n\n this.duplicateConflicts.clear();\n this.isUploading = true;\n this.abortController = new AbortController();\n this.dispatch('statechange');\n\n try {\n await this.client.validateApiKey(false, this.abortController?.signal ?? undefined);\n await this.processUploads();\n this.dispatch('complete', {\n detail: {\n items: this.items,\n files: this.items\n .filter(item => item.status === 'completed')\n .map(item => item.response!)\n .filter(Boolean),\n },\n });\n } catch (error) {\n if (this.isAbortError(error)) {\n this.dispatch('error', { detail: error });\n return;\n }\n this.annotateItemsWithError(error);\n this.dispatch('error', { detail: error });\n throw error;\n } finally {\n this.isUploading = false;\n this.abortController = null;\n this.dispatch('statechange');\n }\n }\n\n cancel() {\n this.abortController?.abort();\n this.abortController = null;\n }\n\n private isDuplicateError(error: unknown) {\n if (!error) return false;\n if (typeof error === 'object' && error !== null) {\n const status = (error as any).status ?? (error as any).statusCode;\n if (status === 409) {\n return true;\n }\n const code = (error as any).code;\n if (typeof code === 'string' && code.toLowerCase() === 'conflict') {\n return true;\n }\n }\n const message =\n error instanceof Error\n ? error.message\n : typeof error === 'string'\n ? error\n : '';\n const normalized = message.toLowerCase();\n return (\n normalized.includes('duplicate') ||\n normalized.includes('already exists') ||\n normalized.includes('status 409') ||\n normalized.includes('conflict 409') ||\n normalized.includes('409')\n );\n }\n\n private markDuplicatesCompleted(\n items: UploadItem[],\n duplicateNames?: string[],\n options: { annotateError?: boolean } = {}\n ): UploadItem[] {\n const normalizedNames =\n duplicateNames\n ?.map(name => name.trim().toLowerCase())\n .filter(Boolean) ?? [];\n const targetSet =\n normalizedNames.length > 0 ? new Set(normalizedNames) : null;\n\n const targetItems =\n targetSet !== null\n ? items.filter(item =>\n targetSet.has(item.file.name.trim().toLowerCase())\n )\n : items;\n\n const duplicates =\n targetSet !== null && targetItems.length === 0 ? items : targetItems;\n\n const { annotateError = true } = options;\n\n duplicates.forEach(item => {\n if (!item) return;\n\n const name = item.file.name;\n if (!this.duplicateConflicts.has(name)) {\n this.duplicateConflicts.add(name);\n }\n\n item.status = 'completed';\n item.progress = 100;\n item.error = annotateError ? 'duplicate' : undefined;\n this.dispatch('fileprogress', { detail: { item } });\n });\n\n if (duplicates.length > 0) {\n this.dispatch('progress', {\n detail: {\n progress: calculateBatchProgress(this.items),\n items: this.items,\n },\n });\n\n this.dispatch('statechange');\n }\n\n return duplicates;\n }\n\n private isAuthError(error: unknown): boolean {\n if (!error || typeof error !== 'object') {\n const message =\n error instanceof Error\n ? error.message\n : typeof error === 'string'\n ? error\n : '';\n return (\n typeof message === 'string' &&\n message.toLowerCase().includes('unauthorized')\n );\n }\n\n const status = (error as any).status;\n if (typeof status === 'number' && (status === 401 || status === 403)) {\n return true;\n }\n\n const message =\n error instanceof Error\n ? error.message\n : typeof (error as any)?.message === 'string'\n ? (error as any).message\n : '';\n const normalized = String(message).toLowerCase();\n return (\n normalized.includes('unauthorized') ||\n normalized.includes('forbidden') ||\n normalized.includes('invalid api key')\n );\n }\n\n private annotateItemsWithError(error: unknown) {\n const isAuth = this.isAuthError(error);\n const fallbackMessage =\n error instanceof Error\n ? error.message\n : typeof (error as any)?.message === 'string'\n ? (error as any).message\n : 'Upload failed';\n\n let mutated = false;\n\n this.items.forEach(item => {\n if (item.status === 'completed') return;\n mutated = true;\n item.status = 'error';\n item.progress = item.progress ?? 0;\n item.error = isAuth ? 'invalid-api-key' : fallbackMessage;\n this.dispatch('fileprogress', { detail: { item } });\n });\n\n if (mutated) {\n this.dispatch('progress', {\n detail: {\n progress: calculateBatchProgress(this.items),\n items: this.items,\n },\n });\n this.dispatch('statechange');\n }\n }\n\n private async processUploads() {\n const allItems = this.items.filter(item => item.status !== 'completed');\n\n if (allItems.length === 0) {\n return;\n }\n\n const parallel = Math.max(1, this.options.parallelUploads ?? DEFAULT_PARALLEL_UPLOADS);\n const uploadSettings = this.options.uploadSettings;\n\n // Process all items in parallel with concurrency limit\n const tasks = allItems.map(item => async () => {\n if (this.abortController?.signal.aborted) {\n throw new Error('Upload cancelled');\n }\n\n try {\n await this.uploadSingleFile(item, uploadSettings);\n } catch (error) {\n if (this.isAbortError(error)) {\n return; // Don't mark as error for aborted uploads\n }\n if (this.isDuplicateError(error)) {\n this.markDuplicatesCompleted([item], [item.file.name], {\n annotateError: true,\n });\n } else {\n const err = error instanceof Error ? error : new Error(String(error));\n item.status = 'error';\n item.error = err.message;\n this.dispatch('fileprogress', { detail: { item } });\n this.dispatch('statechange');\n }\n }\n });\n\n await this.runWithConcurrency(tasks, parallel);\n }\n\n private async uploadSingleFile(\n item: UploadItem,\n uploadSettings?: CreateUploaderOptions['uploadSettings']\n ) {\n // Step 1: Initialize upload - get token and metadata\n item.status = 'uploading';\n item.progress = 0;\n this.dispatch('statechange');\n\n const folderPath = item.folderPath\n ? this.combinePaths(this.options.folderPath, item.folderPath)\n : this.normalizePath(this.options.folderPath);\n\n const initResponse: UploadInitResponse = await this.client.uploadInit(\n {\n fileName: item.file.name,\n fileSize: item.file.size,\n mimeType: item.file.type || 'application/octet-stream',\n path: folderPath,\n settings: uploadSettings\n ? {\n pretransformations: uploadSettings.pretransformations,\n tags: uploadSettings.tags,\n is_unique_suffix_name: uploadSettings.is_unique_suffix_name ?? false,\n }\n : undefined,\n },\n this.abortController?.signal\n );\n\n // Step 2: Upload to App Runner /ingest\n item.progress = 10;\n this.dispatch('fileprogress', { detail: { item } });\n this.dispatch('statechange');\n\n const appRunnerResponse: AppRunnerResponse = await this.client.ingest(\n item.file,\n initResponse.uploadToken,\n initResponse.uploadUrl,\n (progress) => {\n // Map progress from 10-90% (ingest upload)\n item.progress = 10 + Math.round(progress * 0.8);\n this.dispatch('fileprogress', { detail: { item } });\n this.dispatch('progress', {\n detail: {\n progress: calculateBatchProgress(this.items),\n items: this.items,\n },\n });\n },\n this.abortController?.signal\n );\n\n if (!appRunnerResponse.ok) {\n throw new Error(appRunnerResponse.message || 'Upload failed');\n }\n\n // Step 3: Complete upload\n item.progress = 90;\n this.dispatch('fileprogress', { detail: { item } });\n this.dispatch('statechange');\n\n const completeResponse: CompleteUploadResponseNew = await this.client.completeUploadNew(\n {\n uploadId: initResponse.uploadId,\n appRunnerResponse,\n },\n this.abortController?.signal\n );\n\n // Mark as completed\n item.status = 'completed';\n item.progress = 100;\n item.response = {\n file_no: completeResponse.file_no,\n name: completeResponse.name,\n url: completeResponse.url,\n file_size: completeResponse.file_size,\n folder_no: undefined, // Not available in new response\n path: completeResponse.path,\n width: completeResponse.width,\n height: completeResponse.height,\n format: completeResponse.format,\n };\n item.uploadedAt = new Date(completeResponse.created_at);\n\n if (completeResponse.isDuplicate) {\n item.error = 'duplicate';\n }\n\n this.dispatch('fileprogress', { detail: { item } });\n this.dispatch('progress', {\n detail: {\n progress: calculateBatchProgress(this.items),\n items: this.items,\n },\n });\n this.dispatch('statechange');\n }\n\n\n\n private applyTheme() {\n if (!this.options.theme) return;\n const vars = toCssVars(this.options.theme);\n applyCssVariables(this.targetElement, vars);\n if (this.options.theme.appearance && this.options.theme.appearance !== 'system') {\n this.targetElement.dataset.theme = this.options.theme.appearance;\n } else {\n delete this.targetElement.dataset.theme;\n }\n }\n\n private dispatch(event: ControllerEvents, detail?: CustomEventInit['detail']) {\n const customEvent = new CustomEvent(event, { detail });\n this.dispatchEvent(customEvent);\n\n switch (event) {\n case 'progress':\n this.options.onProgress?.(\n (detail as any)?.progress ?? calculateBatchProgress(this.items),\n this.items\n );\n break;\n case 'fileprogress':\n this.options.onFileProgress?.((detail as any).item);\n break;\n case 'error':\n this.options.onError?.(\n detail instanceof Error ? detail : new Error(String(detail))\n );\n break;\n case 'complete':\n this.options.onSuccess?.({\n files: (detail as any)?.files ?? [],\n items: this.items,\n });\n break;\n default:\n break;\n }\n }\n\n private async runWithConcurrency(tasks: Array<() => Promise<void>>, limit: number) {\n const executing = new Set<Promise<void>>();\n\n for (const task of tasks) {\n if (this.abortController?.signal.aborted) {\n throw new Error('Upload cancelled');\n }\n\n const promise = task().finally(() => {\n executing.delete(promise);\n });\n executing.add(promise);\n\n if (executing.size >= limit) {\n await Promise.race(executing);\n }\n }\n\n await Promise.all(executing);\n }\n\n private cleanupPreviews() {\n this.items.forEach(item => {\n if (item.previewUrl) {\n URL.revokeObjectURL(item.previewUrl);\n item.previewUrl = undefined;\n }\n });\n }\n\n private normalizePath(path?: string): string | undefined {\n if (!path) {\n return undefined;\n }\n\n const normalized = path\n .split('/')\n .map(segment => segment.trim())\n .filter(Boolean)\n .join('/');\n\n return normalized.length > 0 ? normalized : undefined;\n }\n\n private combinePaths(basePath?: string, relativePath?: string): string | undefined {\n const base = this.normalizePath(basePath);\n const relative = this.normalizePath(relativePath);\n\n if (base && relative) {\n return `${base}/${relative}`;\n }\n\n return base || relative || undefined;\n }\n\n}\n\n","export const widgetStyles = /* css */ `\n:host {\n --ar-font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n --ar-color-bg: hsl(0 0% 100%);\n --ar-color-bg-muted: hsl(210 40% 96%);\n --ar-color-border: hsl(214 32% 91%);\n --ar-color-text: hsl(222 47% 11%);\n --ar-color-muted-foreground: hsl(215 16% 47%);\n --ar-color-accent: #0C55F9;\n --ar-radius: 8px;\n display: block;\n}\n\n\n:host([data-trigger='inline']) .ar-uploader-root,\n:host([data-trigger='inline']) .ar-inline-upload,\n:host([data-trigger='inline']) .ar-inline-panel {\n width: 100%;\n min-width: 0;\n}\n\n:host([data-theme='dark']) {\n --ar-color-bg: hsl(222 41% 6%);\n --ar-color-bg-muted: hsl(217 33% 17%);\n --ar-color-border: hsl(217 19% 27%);\n --ar-color-text: hsl(213 31% 91%);\n --ar-color-muted-foreground: hsl(215 20% 65%);\n --ar-color-accent: #4C8DFF;\n}\n\n.ar-uploader-root {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n font-family: var(--ar-font-family);\n background-color: var(--ar-color-bg);\n color: var(--ar-color-text);\n border: 1px solid var(--ar-color-border);\n border-radius: var(--ar-radius);\n padding: 0.5rem 1rem 1rem 1rem;\n}\n\n/* Reduce root gap when sources are empty in inline mode */\n:host([data-trigger='inline']) .ar-uploader-root:has(.ar-inline-upload--no-sources) {\n gap: 0.75rem;\n}\n\n\n:host([data-theme='dark']) .ar-uploader-root {\n background-color: hsl(222 41% 6%);\n}\n\n.ar-uploader-root[data-trigger='button'] {\n border: none;\n padding: 0;\n box-shadow: none;\n background: transparent;\n}\n\n.ar-header {\n display: none;\n}\n\n.ar-uploader-root.has-items .ar-header {\n display: flex;\n}\n\n.ar-title {\n margin: 0;\n font-size: 1.25rem;\n font-weight: 600;\n}\n\n.ar-description {\n margin: 0;\n color: var(--ar-color-muted-foreground);\n font-size: 0.95rem;\n}\n\n.ar-subtext {\n margin: 0;\n font-size: 0.8rem;\n color: var(--ar-color-muted-foreground);\n}\n\n.ar-button-trigger {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.45rem;\n padding: 0.55rem 1.25rem;\n font-weight: 600;\n border-radius: var(--ar-radius);\n border: 1px solid rgba(15, 23, 42, 0.08);\n background: rgba(248, 250, 252, 0.9);\n color: var(--ar-color-text);\n cursor: pointer;\n transition: all 0.2s ease;\n box-shadow: 0 6px 16px rgba(15, 23, 42, 0.06);\n}\n\n:host([data-theme='dark']) .ar-button-trigger {\n border: 1px solid rgba(148, 163, 184, 0.25);\n background: rgba(30, 41, 59, 0.75);\n color: var(--ar-color-text);\n}\n\n.ar-button-trigger:hover {\n transform: translateY(-1px);\n}\n\n.ar-button-trigger:active {\n transform: translateY(0);\n}\n\n.ar-button-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.ar-button-icon svg {\n width: 1rem;\n height: 1rem;\n fill: currentColor;\n}\n\n.ar-inline-upload {\n display: flex;\n flex-direction: column;\n gap: 1.1rem;\n}\n\n/* Reduce gap when sources are empty in inline mode */\n:host([data-trigger='inline']) .ar-inline-upload--no-sources {\n gap: 0.5rem;\n}\n\n.ar-inline-panel {\n display: flex;\n flex-direction: column;\n}\n\n.ar-dropzone {\n position: relative;\n border: 1.5px dashed var(--ar-dropzone-border, var(--ar-color-border));\n border-radius: var(--ar-radius);\n background: var(--ar-dropzone-bg, var(--ar-color-bg));\n padding: 3rem 2rem;\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n gap: 1rem;\n cursor: pointer;\n transition: border-color 0.2s ease, background-color 0.2s ease, transform 0.2s ease;\n margin: 0.6rem 0rem 1rem 0rem;\n}\n\n/* Reduce bottom margin when sources are empty in inline mode */\n:host([data-trigger='inline']) .ar-modal-body--no-sources .ar-dropzone {\n margin-bottom: 0.25rem;\n}\n\n.ar-dropzone:hover {\n border-color: var(--ar-color-accent);\n background-color: rgba(12, 85, 249, 0.07);\n transform: translateY(-1px);\n}\n\n.ar-dropzone.is-dragover {\n border-color: var(--ar-color-accent);\n background-color: rgba(12, 85, 249, 0.1);\n}\n\n.ar-dropzone.is-dragging {\n border-color: var(--ar-color-accent);\n background: rgba(12, 85, 249, 0.08);\n color: var(--ar-color-accent);\n}\n\n.ar-dropzone-icon {\n width: 3rem;\n height: 3rem;\n border-radius: 999px;\n background: rgba(12, 85, 249, 0.08);\n color: var(--ar-color-accent);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.ar-dropzone svg {\n width: 1.75rem;\n height: 1.75rem;\n fill: currentColor;\n}\n\n.ar-dropzone-actions {\n display: none;\n}\n\n.ar-file-list {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n margin-bottom: 1rem;\n}\n\n.ar-file-list.is-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));\n gap: 1rem;\n}\n\n.ar-file-item {\n border: none;\n border-radius: var(--ar-radius);\n background: rgba(148, 163, 184, 0.15);\n padding: 0.5rem;\n display: flex;\n flex-direction: column;\n gap: 0.45rem;\n position: relative;\n box-sizing: border-box;\n height: 50px;\n}\n\n.ar-file-item.is-grid {\n height: auto;\n padding: 0px;\n background: none;\n}\n\n:host([data-theme='dark']) .ar-file-item {\n background: hsl(222 41% 10%);\n}\n\n.ar-file-header {\n display: flex;\n align-items: center;\n gap: 0.6rem;\n}\n\n.ar-file-header.is-grid {\n flex-direction: column;\n align-items: stretch;\n}\n\n.ar-file-thumb {\n width: 32px;\n height: 32px;\n border-radius: calc(var(--ar-radius) * 0.5);\n background: rgba(12, 85, 249, 0.1);\n color: var(--ar-color-accent);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.8rem;\n font-weight: 600;\n overflow: hidden;\n position: relative;\n}\n\n.ar-file-thumb.is-grid {\n width: 100%;\n height: 140px;\n border-radius: calc(var(--ar-radius) * 0.75);\n font-size: 1rem;\n}\n\n.ar-file-item.is-completed .ar-file-thumb {\n color: #fff;\n}\n\n.ar-thumb-status {\n position: absolute;\n bottom: -2px;\n right: -2px;\n width: 18px;\n height: 18px;\n border-radius: 999px;\n background: #1e9f6d;\n color: #fff;\n border: 2px solid var(--ar-color-bg);\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 2px 6px rgba(15, 23, 42, 0.25);\n}\n\n.ar-thumb-status svg {\n width: 10px;\n height: 10px;\n color: currentColor;\n}\n\n.ar-thumb-status.is-error {\n background: rgba(225, 29, 72, 0.85);\n}\n\n.ar-file-name {\n font-size: 0.8rem;\n margin: 0;\n color: var(--ar-color-text);\n}\n\n.ar-file-meta {\n display: flex;\n gap: 0.75rem;\n font-size: 0.8rem;\n color: var(--ar-color-muted-foreground);\n}\n\n.ar-file-item.is-grid .ar-file-meta {\n justify-content: center;\n}\n\n.ar-remove-button {\n margin-left: auto;\n border: none;\n background: transparent;\n color: var(--ar-color-muted-foreground);\n cursor: pointer;\n padding: 0.25rem;\n border-radius: var(--ar-radius);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s ease, color 0.2s ease;\n}\n\n.ar-remove-button.is-grid {\n position: absolute;\n top: 0.6rem;\n right: 0.6rem;\n background: rgba(255, 255, 255, 0.95);\n color: var(--ar-color-text);\n padding: 0.35rem;\n border-radius: var(--ar-radius);\n box-shadow: 0 4px 12px rgba(15, 23, 42, 0.25);\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.15s ease, background 0.2s ease, color 0.2s ease;\n}\n\n.ar-file-item.is-grid:hover .ar-remove-button.is-grid {\n opacity: 1;\n pointer-events: auto;\n}\n\n:host([data-theme='dark']) .ar-remove-button.is-grid {\n background: rgba(15, 23, 42, 0.92);\n color: var(--ar-color-text);\n box-shadow: 0 4px 18px rgba(8, 47, 73, 0.45);\n}\n\n.ar-remove-button svg {\n width: 20px;\n height: 20px;\n display: block;\n}\n\n.ar-remove-button svg path,\n.ar-remove-button svg line,\n.ar-remove-button svg rect,\n.ar-remove-button svg circle,\n.ar-remove-button svg polyline {\n stroke: currentColor;\n fill: none;\n}\n\n.ar-remove-button:hover:not([disabled]) {\n color: var(--ar-color-text);\n}\n\n.ar-progress-track {\n width: 100%;\n height: 4px;\n border-radius: var(--ar-radius);\n background-color: rgba(148, 163, 184, 0.35);\n overflow: hidden;\n}\n\n.ar-file-item.is-uploading {\n border-color: var(--ar-color-accent);\n}\n\n.ar-file-item.is-error {\n border: 1px solid rgba(225, 29, 72, 0.4);\n background: rgba(248, 113, 113, 0.12);\n}\n\n.ar-progress-border {\n opacity: 0;\n height: 2px;\n width: 96%;\n border-radius: 999px;\n background: rgba(59, 130, 246, 0.18);\n overflow: hidden;\n margin-top: 0.35rem;\n position: absolute;\n bottom: 0;\n left: 6px;\n right: 6px;\n}\n\n.ar-progress-border.is-active,\n.ar-progress-border.is-complete {\n opacity: 1;\n}\n\n.ar-progress-border.is-train {\n background: rgba(59, 130, 246, 0.18);\n}\n\n.ar-progress-fill {\n height: 100%;\n width: 0%;\n border-radius: inherit;\n background: linear-gradient(90deg, #3b82f6 0%, #2563eb 100%);\n transition: width 0.25s ease;\n transform-origin: left center;\n animation: none;\n}\n\n.ar-progress-fill.is-train {\n background-image: linear-gradient(\n 90deg,\n rgba(245, 250, 241, 0.93) 0%,\n rgba(240, 242, 247, 0.85) 80%,\n rgb(30, 101, 212) 100%\n );\n background-size: 220% 100%;\n animation: ar-progress-train 2.4s linear infinite;\n}\n\n.ar-progress-border.is-complete {\n background: rgba(34, 197, 94, 0.25);\n}\n\n.ar-progress-border.is-complete .ar-progress-fill {\n background-image: linear-gradient(\n 90deg,\n rgba(52, 211, 153, 0.3) 0%,\n rgba(16, 185, 129, 0.85) 50%,\n rgba(52, 211, 153, 0.3) 100%\n );\n animation: none;\n}\n\n@keyframes ar-progress-train {\n 0% {\n background-position: 240% 0;\n }\n 100% {\n background-position: -240% 0;\n }\n}\n\n.ar-file-item.is-completed {\n border-color: rgba(30, 159, 109, 0.6);\n}\n\n.ar-file-item.is-grid .ar-file-name {\n text-align: left;\n font-size: 0.78rem;\n color: var(--ar-color-muted-foreground);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.ar-status {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n font-size: 0.8rem;\n font-weight: 500;\n color: var(--ar-color-muted-foreground);\n}\n\n.ar-status svg {\n width: 1rem;\n height: 1rem;\n}\n\n.ar-status.is-success {\n color: #1e9f6d;\n}\n\n.ar-status.is-error {\n color: #e11d48;\n}\n\n.ar-status.is-warning {\n color: #d97706;\n}\n\n.ar-file-error {\n font-size: 0.78rem;\n color: #e11d48;\n}\n\n.ar-error-banner {\n display: none;\n margin: 0.5rem 0;\n color: #b91c1c;\n font-size: 0.82rem;\n font-weight: 600;\n line-height: 1.4;\n}\n\n.ar-error-banner:not([hidden]) {\n display: block;\n}\n\n:host([data-theme='dark']) .ar-error-banner {\n color: #fecaca;\n}\n\n.ar-actions {\n display: flex;\n justify-content: flex-end;\n}\n\n.ar-upload-button {\n border-radius: 10px;\n padding: 0.65rem 1.5rem;\n font-weight: 600;\n border: none;\n background: var(--ar-color-accent);\n color: white;\n cursor: pointer;\n transition: filter 0.2s ease, transform 0.2s ease;\n min-width: 140px;\n}\n\n.ar-upload-button:hover:not([disabled]) {\n filter: brightness(1.05);\n transform: translateY(-1px);\n}\n\n.ar-upload-button[disabled] {\n opacity: 0.55;\n cursor: not-allowed;\n}\n\n.ar-footer {\n font-size: 0.78rem;\n color: var(--ar-color-muted-foreground);\n text-align: right;\n}\n\n.ar-modal {\n position: fixed;\n inset: 0;\n display: none;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n}\n\n.ar-modal.is-open {\n display: flex;\n}\n\n.ar-modal-backdrop {\n position: absolute;\n inset: 0;\n background: rgba(15, 23, 42, 0.45);\n}\n\n.ar-modal-dialog {\n position: relative;\n background: var(--ar-color-bg);\n border-radius: 16px;\n border: 1px solid var(--ar-color-border);\n box-shadow: 0 32px 80px rgba(15, 23, 42, 0.25);\n width: min(460px, 92vw);\n max-height: 90vh;\n display: flex;\n flex-direction: column;\n padding: 0.5rem 1rem 1rem 1rem;\n}\n\n.ar-modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 1rem;\n margin-bottom: 1rem;\n}\n\n.ar-modal-header.is-inline {\n justify-content: flex-start;\n align-items: center;\n gap: 0.5rem;\n padding-top:0.5rem;\n}\n\n.ar-modal-title {\n margin: 0;\n font-size: 1rem;\n font-weight: 500;\n}\n\n.ar-modal-close {\n border: none;\n background: transparent;\n color: var(--ar-color-muted-foreground);\n cursor: pointer;\n border-radius: 999px;\n padding: 0.3rem;\n transition: color 0.2s ease, background 0.2s ease;\n}\n\n.ar-modal-close:hover {\n background: rgba(148, 163, 184, 0.15);\n color: var(--ar-color-accent);\n}\n\n.ar-modal-close-icon svg {\n width: 1.2rem;\n height: 1.2rem;\n}\n\n.ar-modal-body {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n overflow-y: auto;\n padding-right: 0.25rem;\n}\n\n/* Reduce gap when source list is hidden in inline mode */\n:host([data-trigger='inline']) .ar-modal-body--no-sources {\n gap: 0.5rem;\n}\n\n.ar-modal-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 1rem;\n}\n\n.ar-modal-footer.is-inline {\n padding: 0;\n border-top: none;\n}\n\n.ar-modal-footer.is-inline .ar-modal-footer-actions {\n margin-left: auto;\n}\n\n.ar-modal-footer-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.ar-modal-add-more,\n.ar-modal-clear {\n border-radius: var(--ar-radius);\n padding: 0.55rem 1.25rem;\n font-weight: 600;\n border: 1px solid var(--ar-color-border);\n background: var(--ar-color-bg);\n color: var(--ar-color-text);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.ar-modal-add-more:hover {\n border-color: var(--ar-color-accent);\n color: var(--ar-color-accent);\n}\n\n.ar-modal-clear {\n background: rgba(148, 163, 184, 0.12);\n}\n\n.ar-modal-clear[disabled] {\n opacity: 0.45;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n.ar-modal-clear:hover {\n border-color: var(--ar-color-accent);\n color: var(--ar-color-accent);\n}\n\n.ar-modal-upload-button,\n.ar-modal-done {\n border-radius: var(--ar-radius);\n padding: 0.55rem 1.25rem;\n font-weight: 600;\n border: none;\n background: var(--ar-color-accent);\n color: white;\n cursor: pointer;\n transition: filter 0.2s ease;\n}\n\n.ar-modal-upload-button:hover,\n.ar-modal-done:hover {\n filter: brightness(1.05);\n}\n\n.ar-uploaded-summary {\n display: flex;\n flex-direction: column;\n gap: 0.85rem;\n border-top: 1px solid var(--ar-color-border);\n padding-top: 1rem;\n}\n\n.ar-uploader-root[data-trigger='button'] .ar-uploaded-summary {\n border: 1px solid var(--ar-color-border);\n border-radius: var(--ar-radius);\n padding: 1rem;\n background: var(--ar-color-bg-muted);\n}\n\n.ar-summary-title {\n margin: 0;\n font-size: 0.95rem;\n font-weight: 600;\n}\n\n.ar-summary-list {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.ar-summary-item {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.ar-summary-icon {\n width: 38px;\n height: 38px;\n border-radius: 12px;\n background: rgba(12, 85, 249, 0.12);\n color: var(--ar-color-accent);\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 600;\n}\n\n.ar-summary-info {\n display: flex;\n flex-direction: column;\n gap: 0.2rem;\n}\n\n.ar-summary-name {\n font-weight: 600;\n font-size: 0.95rem;\n}\n\n.ar-summary-meta {\n font-size: 0.8rem;\n color: var(--ar-color-muted-foreground);\n}\n\n.ar-uploader-root.is-uploading .ar-dropzone {\n display: none;\n}\n\n.ar-uploader-root.has-items .ar-file-list {\n display: flex;\n}\n\n.ar-file-list:empty {\n display: none;\n}\n\n.ar-modal-upload {\n display: flex;\n flex-direction: column;\n}\n\n.ar-modal-upload.is-inline {\n gap: 1rem;\n}\n\n.ar-modal-body .ar-file-list {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n max-height: 220px;\n overflow-y: auto;\n border: none;\n background: transparent;\n padding: 0;\n}\n\nbutton,\n.ar-button-trigger,\n.ar-dropzone-button,\n.ar-upload-button,\n.ar-modal-footer button,\n.ar-actions button,\n.ar-remove-button,\n.ar-modal-header button {\n font-size: 1rem;\n font-weight: 400;\n}\n\n@media (max-width: 640px) {\n .ar-uploader-root {\n padding: 1rem;\n }\n\n .ar-dropzone {\n padding: 2.25rem 1.25rem;\n }\n\n .ar-modal-dialog {\n width: min(90vw, 420px);\n padding: 1.25rem;\n }\n}\n\n.ar-actions-sources,\n.ar-modal-sources {\n display: none;\n}\n\n.ar-actions-sources.is-visible,\n.ar-modal-sources.is-visible {\n display: flex;\n gap: 0.5rem;\n align-items: center;\n}\n\n.ar-source-list {\n display: none;\n flex-direction: column;\n margin: 1rem 0rem;\n}\n\n/* Remove margin when source list is hidden in inline mode */\n:host([data-trigger='inline']) .ar-source-list:not(.ar-source-list--choices) {\n margin: 0;\n}\n\n.ar-source-list--choices {\n display: flex;\n}\n\n.ar-source-option {\n display: flex;\n align-items: center;\n gap: 0.65rem;\n width: 100%;\n border: none;\n border-radius: var(--ar-radius);\n background: transparent;\n padding: 0.55rem 0.75rem;\n text-align: left;\n color: var(--ar-color-text);\n cursor: pointer;\n transition: background-color 0.2s ease, color 0.2s ease;\n}\n\n.ar-source-option.is-primary {\n background: rgba(12, 85, 249, 0.12);\n color: var(--ar-color-accent);\n}\n\n.ar-source-option:hover:not([disabled]),\n.ar-source-option:focus-visible {\n background: rgba(12, 85, 249, 0.08);\n color: var(--ar-color-accent);\n}\n\n.ar-source-option[disabled] {\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n.ar-source-option-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n color: var(--ar-color-muted-foreground);\n}\n\n.ar-source-option-label {\n flex: 1;\n font-size: 0.95rem;\n}\n\n.ar-source-inline {\n display: flex;\n gap: 0.5rem;\n align-items: center;\n}\n\n.ar-source-inline-button {\n width: 36px;\n height: 36px;\n border-radius: 999px;\n border: 1px solid var(--ar-color-border);\n background: transparent;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: var(--ar-color-text);\n transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;\n}\n\n.ar-source-inline-button:hover:not([disabled]) {\n background: rgba(12, 85, 249, 0.12);\n color: var(--ar-color-accent);\n border-color: rgba(12, 85, 249, 0.2);\n}\n\n.ar-source-inline-button svg {\n width: 18px;\n height: 18px;\n display: block;\n}\n\n.ar-modal-cancel {\n background: rgba(148, 163, 184, 0.15);\n border: none;\n color: var(--ar-color-text);\n padding:0.5rem 1rem;\n border-radius: var(--ar-radius);\n}\n\n.ar-modal-cancel:hover:not([disabled]) {\n background: rgba(148, 163, 184, 0.25);\n}\n\n.ar-modal-cancel.is-fullwidth {\n width: 100%;\n justify-content: center;\n border-radius: var(--ar-radius);\n cursor: pointer;\n}\n\n.ar-modal-powered,\n.ar-inline-powered {\n margin-top: 12px;\n font-size: 0.75rem;\n color: var(--ar-color-muted-foreground);\n text-align: center;\n}\n\n/* Reduce margin when sources are empty in inline mode */\n:host([data-trigger='inline']) .ar-inline-upload--no-sources .ar-inline-powered {\n margin-top: 0.5rem;\n}\n\n.ar-duplicate-banner {\n display: none;\n margin: 0.75rem 0;\n padding: 0.75rem;\n border-radius: var(--ar-radius);\n background: rgba(248, 113, 113, 0.12);\n color: #9f1239;\n font-size: 0.85rem;\n line-height: 1.3;\n}\n\n.ar-duplicate-banner[hidden] {\n display: none !important;\n}\n\n`;\n\n","import { UploaderController, type ControllerOptions } from '../core/uploader-controller';\nimport { DEFAULT_ICONS, DEFAULT_LABELS, DEFAULT_THEME } from '../constants/defaults';\nimport type {\n IconSet,\n LabelSet,\n ThemeOptions,\n UploadItem,\n UploadSourceOption,\n UploaderClassNames,\n} from '../types';\nimport { resolveIcon } from '../utils/helpers';\nimport { widgetStyles } from './styles';\n\ninterface FilesAddedDetail {\n items: UploadItem[];\n}\n\ninterface FileSystemEntry {\n isFile: boolean;\n isDirectory: boolean;\n name: string;\n fullPath: string;\n}\n\ninterface FileSystemFileEntry extends FileSystemEntry {\n file: (callback: (file: File) => void, errorCallback?: (error: DOMException) => void) => void;\n}\n\ninterface FileSystemDirectoryEntry extends FileSystemEntry {\n createReader: () => FileSystemDirectoryReader;\n}\n\ninterface FileSystemDirectoryReader {\n readEntries: (\n successCallback: (entries: FileSystemEntry[]) => void,\n errorCallback?: (error: DOMException) => void\n ) => void;\n}\n\nexport class AutorenderUploaderElement extends HTMLElement {\n static tagName = 'autorender-uploader';\n\n private shadow: ShadowRoot;\n private controller: UploaderController | null = null;\n private options!: ControllerOptions;\n private labels: Required<LabelSet> = DEFAULT_LABELS;\n private icons: Required<IconSet> = DEFAULT_ICONS;\n private classNames: UploaderClassNames = {};\n private sourceOptions: UploadSourceOption[] = [];\n\n private triggerType: 'button' | 'inline' = 'inline';\n private isModalOpen = false;\n private fileLayout: 'list' | 'grid' = 'list';\n private showGridFileName = true;\n\n private rootElement: HTMLElement | null = null;\n private fileInput!: HTMLInputElement;\n private dropzone: HTMLDivElement | null = null;\n private fileList: HTMLUListElement | null = null;\n private sourceLists: HTMLElement[] = [];\n private modalBody: HTMLElement | null = null;\n private inlineUpload: HTMLElement | null = null;\n private uploadButton: HTMLButtonElement | null = null;\n private triggerButton: HTMLButtonElement | null = null;\n private modalElement: HTMLElement | null = null;\n private modalCloseButton: HTMLButtonElement | null = null;\n private modalDoneButton: HTMLButtonElement | null = null;\n private modalClearButton: HTMLButtonElement | null = null;\n private modalUploadButton: HTMLButtonElement | null = null;\n private modalCancelButton: HTMLButtonElement | null = null;\n private modalAddMoreButton: HTMLButtonElement | null = null;\n private modalFooterActions: HTMLElement | null = null;\n private modalSourceContainer: HTMLElement | null = null;\n private actionsSourceContainer: HTMLElement | null = null;\n private modalTitleElement: HTMLElement | null = null;\n private modalHeaderElement: HTMLElement | null = null;\n private modalPoweredElement: HTMLElement | null = null;\n private inlinePoweredElement: HTMLElement | null = null;\n private duplicateBanners: HTMLElement[] = [];\n private errorBannerElement: HTMLElement | null = null;\n private globalErrorMessage: string | null = null;\n\n private isAbortError(error: unknown): boolean {\n if (!error) return false;\n if (error instanceof DOMException && error.name === 'AbortError') return true;\n if (error instanceof Error && error.name === 'AbortError') return true;\n const message =\n error instanceof Error\n ? error.message\n : typeof error === 'string'\n ? error\n : '';\n return typeof message === 'string' && message.toLowerCase().includes('abort');\n }\n\n private controllerListeners = new Map<string, (event: Event) => void>();\n private handleKeydown = (event: KeyboardEvent) => {\n if (event.key === 'Escape' && this.isModalOpen) {\n this.isModalOpen = false;\n this.render();\n }\n };\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback() {\n this.render();\n }\n\n disconnectedCallback() {\n this.detachController();\n window.removeEventListener('keydown', this.handleKeydown);\n }\n\n setController(controller: UploaderController, options: ControllerOptions) {\n this.detachController();\n this.controller = controller;\n this.globalErrorMessage = null;\n this.applyOptions(options);\n this.attachController();\n this.render();\n }\n\n updateOptions(options: Partial<ControllerOptions>) {\n if (!this.controller) return;\n this.applyOptions({ ...this.options, ...options });\n this.controller.setOptions(this.options);\n this.render();\n }\n\n openFileDialog() {\n if (this.triggerType === 'button' && !this.isModalOpen) {\n this.isModalOpen = true;\n this.render();\n requestAnimationFrame(() => this.fileInput?.click());\n return;\n }\n this.fileInput?.click();\n }\n\n private applyOptions(options: ControllerOptions) {\n const previousOptions = this.options ?? ({} as ControllerOptions);\n const themeInput = (options.theme ?? previousOptions.theme ?? DEFAULT_THEME) as ThemeOptions;\n const resolvedTheme = {\n appearance: themeInput.appearance ?? DEFAULT_THEME.appearance,\n accentColor: themeInput.accentColor ?? DEFAULT_THEME.accentColor,\n borderRadius: themeInput.borderRadius ?? DEFAULT_THEME.borderRadius,\n dropzoneBackground: themeInput.dropzoneBackground ?? DEFAULT_THEME.dropzoneBackground,\n dropzoneBorder: themeInput.dropzoneBorder ?? DEFAULT_THEME.dropzoneBorder,\n fontFamily: themeInput.fontFamily ?? previousOptions.theme?.fontFamily,\n };\n\n // Sources are already normalized by normalizeOptions (empty array if all disabled)\n const resolvedSources = options.sources ?? previousOptions.sources ?? [];\n const previousSourceIds = this.sourceOptions?.map(s => s.id).sort().join(',') ?? '';\n\n this.options = {\n ...previousOptions,\n ...options,\n theme: resolvedTheme,\n sources: resolvedSources,\n };\n\n this.labels = {\n ...DEFAULT_LABELS,\n ...(this.options.labels ?? {}),\n };\n\n this.icons = DEFAULT_ICONS;\n\n const currentSourceIds = resolvedSources.map(s => s.id).sort().join(',');\n const sourcesChanged = previousSourceIds !== currentSourceIds;\n \n this.sourceOptions = resolvedSources;\n this.options.onSourceSelect = options.onSourceSelect ?? previousOptions.onSourceSelect;\n\n const requestedType = this.options.type ?? 'inline';\n this.triggerType = requestedType === 'button' ? 'button' : 'inline';\n this.fileLayout = this.options.fileLayout ?? 'list';\n this.showGridFileName = this.options.showGridFileName ?? true;\n this.classNames = this.options.classNames ?? {};\n\n if (this.options.autoUpload === undefined && this.triggerType === 'inline') {\n this.options.autoUpload = true;\n }\n\n // Re-render source list if sources changed and widget is already rendered\n if (this.rootElement && sourcesChanged) {\n const hasItems = this.controller?.getState().items.length > 0 ?? false;\n this.renderSourceOptions(hasItems);\n }\n }\n\n private attachController() {\n if (!this.controller) return;\n\n const stateListener = () => this.updateState();\n const progressListener = () => this.updateState();\n const filesAddedListener = (event: Event) => {\n const detail = (event as CustomEvent<FilesAddedDetail>).detail;\n if (this.options.autoUpload && detail?.items?.length) {\n void this.controller?.uploadAll();\n }\n };\n const completeListener = () => {\n this.clearGlobalError();\n this.render();\n };\n const errorListener = (event: Event) => {\n const detail = (event as CustomEvent).detail;\n this.handleControllerError(detail);\n };\n\n this.controller.addEventListener('statechange', stateListener);\n this.controller.addEventListener('progress', progressListener);\n this.controller.addEventListener('fileprogress', progressListener);\n this.controller.addEventListener('filesadded', filesAddedListener);\n this.controller.addEventListener('complete', completeListener);\n this.controller.addEventListener('error', errorListener);\n\n this.controllerListeners.set('statechange', stateListener);\n this.controllerListeners.set('progress', progressListener);\n this.controllerListeners.set('fileprogress', progressListener);\n this.controllerListeners.set('filesadded', filesAddedListener);\n this.controllerListeners.set('complete', completeListener);\n this.controllerListeners.set('error', errorListener);\n }\n\n private detachController() {\n if (!this.controller) return;\n for (const [event, handler] of this.controllerListeners.entries()) {\n this.controller.removeEventListener(event, handler);\n }\n this.controllerListeners.clear();\n this.controller = null;\n }\n\n private resolveClassName(key: keyof UploaderClassNames, fallback: string) {\n const extra = this.classNames[key];\n return extra ? `${fallback} ${extra}` : fallback;\n }\n\n private render() {\n if (!this.controller) return;\n\n this.setAttribute('data-trigger', this.triggerType);\n\n const duplicateBannerMarkup = `<div class=\"ar-duplicate-banner\" hidden></div>`;\n const errorBannerMarkup = `<div class=\"ar-error-banner\" role=\"alert\" hidden></div>`;\n\n const dropzoneMarkup = `\n <div class=\"${this.resolveClassName('dropzone', 'ar-dropzone')}\" role=\"button\" tabindex=\"0\">\n <div class=\"ar-dropzone-icon\"></div>\n <p class=\"ar-description\">${this.labels.dropzoneTitle}</p>\n </div>\n `;\n\n const fileListMarkup = `<ul class=\"${this.resolveClassName('fileList', 'ar-file-list')}\"></ul>`;\n const sourceListMarkup = '<div class=\"ar-source-list\"></div>';\n\n const modalHeaderMarkup = `\n <div class=\"ar-modal-header\">\n <h3 class=\"ar-modal-title\">${this.labels.title}</h3>\n <button type=\"button\" class=\"ar-modal-close\" aria-label=\"Close\"><span class=\"ar-modal-close-icon\"></span></button>\n </div>\n `;\n\n const inlineHeaderMarkup = `\n <div class=\"ar-modal-header is-inline\">\n <h3 class=\"ar-modal-title\">${this.labels.title}</h3>\n </div>\n `;\n\n const uploadPanelMarkup = `\n <div class=\"ar-modal-body\">\n <div class=\"ar-modal-upload${this.triggerType === 'inline' ? ' is-inline' : ''}\">\n ${dropzoneMarkup}\n ${errorBannerMarkup}\n ${duplicateBannerMarkup}\n ${sourceListMarkup}\n ${fileListMarkup}\n </div>\n </div>\n `;\n\n const footerMarkup = `\n <div class=\"ar-modal-footer${this.triggerType === 'inline' ? ' is-inline' : ''}\">\n <button type=\"button\" class=\"ar-modal-clear\">${this.labels.clear}</button>\n <button type=\"button\" class=\"ar-modal-cancel\">${this.labels.cancel}</button>\n <div class=\"ar-modal-footer-actions\">\n <div class=\"ar-modal-sources\"></div>\n <button type=\"button\" class=\"ar-modal-add-more\">${this.labels.addMore}</button>\n <button type=\"button\" class=\"ar-modal-upload-button\">${this.labels.uploadButton}</button>\n <button type=\"button\" class=\"ar-modal-done\">${this.labels.done}</button>\n </div>\n </div>\n `;\n\n const modalMarkup = this.triggerType === 'button'\n ? `\n <div class=\"${this.resolveClassName('modal', 'ar-modal')} ${this.isModalOpen ? 'is-open' : ''}\">\n <div class=\"ar-modal-backdrop\"></div>\n <div class=\"ar-modal-dialog\">\n ${modalHeaderMarkup}\n ${uploadPanelMarkup}\n ${footerMarkup}\n <div class=\"ar-modal-powered\">Powered by Autorender</div>\n </div>\n </div>\n `\n : '';\n\n const inlineMarkup = this.triggerType === 'inline'\n ? `\n <div class=\"ar-inline-upload\">\n <div class=\"ar-inline-panel\">\n ${inlineHeaderMarkup}\n ${uploadPanelMarkup}\n ${footerMarkup}\n </div>\n <div class=\"ar-inline-powered\">Powered by Autorender</div>\n </div>\n `\n : '';\n\n const template = document.createElement('template');\n template.innerHTML = `\n <style>${widgetStyles}</style>\n <div class=\"${this.resolveClassName('root', 'ar-uploader-root')}\" data-trigger=\"${this.triggerType}\">\n <input type=\"file\" class=\"ar-file-input\" hidden />\n ${\n this.triggerType === 'button'\n ? `<button type=\"button\" class=\"${this.resolveClassName('triggerButton', 'ar-button-trigger')}\" ${\n this.isModalOpen ? 'style=\"display: none;\"' : ''\n }><span class=\"ar-button-icon\"></span><span>${this.labels.selectButton}</span></button>`\n : inlineMarkup\n }\n ${modalMarkup}\n </div>\n `;\n\n this.shadow.innerHTML = '';\n this.shadow.appendChild(template.content.cloneNode(true));\n\n this.captureElements();\n this.applyDimensions();\n this.configureInputs();\n this.bindEvents();\n this.applyThemeVariables();\n this.updateState();\n\n if (this.triggerType === 'button') {\n if (this.isModalOpen) {\n window.addEventListener('keydown', this.handleKeydown);\n } else {\n window.removeEventListener('keydown', this.handleKeydown);\n }\n }\n }\n\n private captureElements() {\n this.rootElement = this.shadow.querySelector('.ar-uploader-root');\n this.fileInput = this.shadow.querySelector('.ar-file-input') as HTMLInputElement;\n this.dropzone = this.shadow.querySelector('.ar-dropzone');\n this.fileList = this.shadow.querySelector('.ar-file-list');\n this.sourceLists = Array.from(this.shadow.querySelectorAll('.ar-source-list')) as HTMLElement[];\n this.modalBody = this.shadow.querySelector('.ar-modal-body');\n this.inlineUpload = this.shadow.querySelector('.ar-inline-upload');\n this.uploadButton = this.shadow.querySelector('.ar-upload-button');\n this.triggerButton = this.shadow.querySelector('.ar-button-trigger');\n this.modalElement = this.shadow.querySelector('.ar-modal');\n this.modalCloseButton = this.shadow.querySelector('.ar-modal-close') as HTMLButtonElement | null;\n this.modalDoneButton = this.shadow.querySelector<HTMLButtonElement>('.ar-modal-done');\n this.modalClearButton = this.shadow.querySelector<HTMLButtonElement>('.ar-modal-clear');\n this.modalUploadButton = this.shadow.querySelector<HTMLButtonElement>('.ar-modal-upload-button');\n this.modalCancelButton = this.shadow.querySelector('.ar-modal-cancel') as HTMLButtonElement | null;\n this.modalAddMoreButton = this.shadow.querySelector('.ar-modal-add-more') as HTMLButtonElement | null;\n this.modalFooterActions = this.shadow.querySelector('.ar-modal-footer-actions');\n this.modalSourceContainer = this.shadow.querySelector('.ar-modal-sources');\n this.actionsSourceContainer = this.shadow.querySelector('.ar-actions-sources');\n this.modalTitleElement = this.shadow.querySelector('.ar-modal-title');\n this.modalHeaderElement = this.shadow.querySelector('.ar-modal-header');\n this.modalPoweredElement = this.shadow.querySelector('.ar-modal-powered');\n this.inlinePoweredElement = this.shadow.querySelector('.ar-inline-powered');\n this.duplicateBanners = Array.from(\n this.shadow.querySelectorAll('.ar-duplicate-banner')\n ) as HTMLElement[];\n this.errorBannerElement = this.shadow.querySelector('.ar-error-banner') as HTMLElement | null;\n this.updateErrorBanner();\n\n const icon = resolveIcon(this.icons.upload);\n const iconContainer = this.shadow.querySelector('.ar-dropzone-icon');\n if (icon && iconContainer) {\n iconContainer.innerHTML = '';\n iconContainer.appendChild(icon);\n }\n const buttonIcon = resolveIcon(this.icons.upload);\n const triggerIconContainer = this.shadow.querySelector('.ar-button-icon');\n if (buttonIcon && triggerIconContainer) {\n triggerIconContainer.innerHTML = '';\n triggerIconContainer.appendChild(buttonIcon);\n }\n const closeIcon = resolveIcon(this.icons.close);\n const closeIconContainer = this.shadow.querySelector('.ar-modal-close-icon');\n if (closeIcon && closeIconContainer) {\n closeIconContainer.innerHTML = '';\n closeIconContainer.appendChild(closeIcon);\n }\n }\n\n private applyDimensions() {\n if (!this.rootElement) return;\n\n const requestedWidth = this.options.width;\n\n if (requestedWidth === undefined || requestedWidth === null || requestedWidth === '') {\n if (this.triggerType === 'inline') {\n this.rootElement.style.width = '100%';\n } else {\n this.rootElement.style.removeProperty('width');\n }\n return;\n }\n\n const normalizedWidth =\n typeof requestedWidth === 'number' ? `${requestedWidth}px` : requestedWidth;\n this.rootElement.style.width = normalizedWidth;\n }\n\n private configureInputs() {\n this.fileInput?.removeAttribute('webkitdirectory');\n this.fileInput?.removeAttribute('mozdirectory');\n this.fileInput?.removeAttribute('directory');\n\n if (this.options.allowMultiple === false) {\n this.fileInput?.removeAttribute('multiple');\n } else {\n this.fileInput?.setAttribute('multiple', '');\n }\n\n if (this.options.accept?.length) {\n this.fileInput.accept = this.options.accept.join(',');\n }\n }\n\n private bindEvents() {\n this.triggerButton?.addEventListener('click', () => {\n this.isModalOpen = true;\n this.render();\n });\n\n this.modalCloseButton?.addEventListener('click', () => {\n this.isModalOpen = false;\n this.render();\n });\n\n this.modalElement?.addEventListener('click', event => {\n const target = event.target as HTMLElement;\n if (!target) return;\n if (target === this.modalElement || target.classList.contains('ar-modal-backdrop')) {\n this.isModalOpen = false;\n this.render();\n }\n });\n\n this.modalUploadButton?.addEventListener('click', () => {\n if (!this.controller) return;\n if (this.controller.getState().isUploading) return;\n void this.controller.uploadAll();\n });\n\n this.modalDoneButton?.addEventListener('click', () => {\n if (!this.controller) return;\n const state = this.controller.getState();\n const allCompleted = state.items.length > 0 && state.items.every(item => item.status === 'completed');\n if (this.triggerType === 'inline') {\n if (state.isUploading) {\n return;\n }\n if (allCompleted || state.items.length === 0) {\n this.controller.reset();\n this.updateState();\n }\n return;\n }\n if (state.isUploading) {\n this.closeModal();\n return;\n }\n if (allCompleted) {\n this.closeModal();\n return;\n }\n this.closeModal();\n });\n\n this.modalClearButton?.addEventListener('click', () => {\n if (!this.controller) return;\n const { isUploading } = this.controller.getState();\n if (isUploading) {\n return;\n }\n this.controller.reset();\n this.updateState();\n });\n\n this.modalCancelButton?.addEventListener('click', () => {\n if (!this.controller) return;\n const currentState = this.controller.getState();\n if (currentState.isUploading) return;\n this.controller.reset();\n if (this.triggerType === 'inline') {\n this.updateState();\n return;\n }\n this.isModalOpen = false;\n this.render();\n });\n\n this.modalAddMoreButton?.addEventListener('click', () => {\n this.openFileDialog();\n });\n\n this.dropzone?.addEventListener('click', () => this.openFileDialog());\n this.dropzone?.addEventListener('dragenter', event => {\n event.preventDefault();\n this.dropzone?.classList.add('is-dragging');\n });\n this.dropzone?.addEventListener('dragover', event => {\n event.preventDefault();\n this.dropzone?.classList.add('is-dragging');\n if (event.dataTransfer) {\n event.dataTransfer.dropEffect = 'copy';\n }\n });\n this.dropzone?.addEventListener('dragleave', event => {\n if (event.target === this.dropzone) {\n this.dropzone?.classList.remove('is-dragging');\n }\n });\n this.dropzone?.addEventListener('drop', async event => {\n event.preventDefault();\n this.dropzone?.classList.remove('is-dragging');\n const files = await this.extractFilesFromEvent(event);\n if (files.length) {\n this.controller?.addFiles(files);\n }\n if (this.fileInput) {\n this.fileInput.value = '';\n }\n });\n\n this.fileInput?.addEventListener('change', () => {\n const files = this.fileInput?.files ? Array.from(this.fileInput.files) : [];\n const mapped = files.map(file => ({\n file,\n relativePath: (file as File & { webkitRelativePath?: string }).webkitRelativePath,\n }));\n this.controller?.addFiles(mapped);\n if (this.fileInput) this.fileInput.value = '';\n });\n\n this.uploadButton?.addEventListener('click', () => {\n if (this.controller?.getState().isUploading) return;\n void this.controller?.uploadAll();\n });\n }\n\n private async extractFilesFromEvent(\n event: DragEvent\n ): Promise<Array<{ file: File; relativePath?: string }>> {\n const items = event.dataTransfer?.items;\n\n if (!items) {\n const files = event.dataTransfer?.files ? Array.from(event.dataTransfer.files) : [];\n return files.map(file => ({\n file,\n relativePath: (file as File & { webkitRelativePath?: string }).webkitRelativePath,\n }));\n }\n\n const entries = Array.from(items)\n .map(item => (item.webkitGetAsEntry ? item.webkitGetAsEntry() : null))\n .filter(Boolean) as FileSystemEntry[];\n\n const collected: Array<{ file: File; relativePath?: string }> = [];\n\n for (const entry of entries) {\n const files = await this.readEntry(entry, '');\n collected.push(...files);\n }\n\n return collected;\n }\n\n private readEntry(entry: FileSystemEntry, path = ''): Promise<Array<{ file: File; relativePath?: string }>> {\n return new Promise(resolve => {\n if (entry.isFile) {\n (entry as FileSystemFileEntry).file(file => {\n resolve([{ file, relativePath: path ? `${path}/${file.name}` : file.name }]);\n });\n } else if (entry.isDirectory) {\n const reader = (entry as FileSystemDirectoryEntry).createReader();\n reader.readEntries(async entries => {\n const results = await Promise.all(\n entries.map(child => this.readEntry(child, path ? `${path}/${entry.name}` : entry.name))\n );\n resolve(results.flat());\n });\n } else {\n resolve([]);\n }\n });\n }\n\n private closeModal() {\n this.isModalOpen = false;\n this.render();\n }\n\n private setGlobalError(message: string | null) {\n this.globalErrorMessage = message;\n this.updateErrorBanner();\n }\n\n private clearGlobalError() {\n this.setGlobalError(null);\n }\n\n private updateErrorBanner() {\n if (!this.errorBannerElement) return;\n if (this.globalErrorMessage) {\n this.errorBannerElement.hidden = false;\n this.errorBannerElement.textContent = this.globalErrorMessage;\n } else {\n this.errorBannerElement.hidden = true;\n this.errorBannerElement.textContent = '';\n }\n }\n\n private handleControllerError(error: unknown) {\n if (this.isAbortError(error)) {\n this.clearGlobalError();\n return;\n }\n\n const status =\n typeof error === 'object' && error !== null && 'status' in error\n ? (error as any).status\n : undefined;\n const messageCandidate =\n error instanceof Error\n ? error.message\n : typeof (error as any)?.message === 'string'\n ? (error as any).message\n : typeof error === 'string'\n ? error\n : '';\n\n const normalized = String(messageCandidate ?? '').toLowerCase();\n const isAuthError =\n (typeof status === 'number' && (status === 401 || status === 403)) ||\n normalized.includes('unauthorized') ||\n normalized.includes('forbidden') ||\n normalized.includes('invalid api key');\n\n if (isAuthError) {\n this.setGlobalError(this.labels.invalidApiKey);\n } else if (messageCandidate) {\n this.setGlobalError(String(messageCandidate));\n } else {\n this.setGlobalError(this.labels.uploadFailed);\n }\n }\n\n private updateState() {\n if (!this.controller) return;\n if (!this.fileList) return;\n\n const state = this.controller.getState();\n const { items, isUploading, duplicates } = state;\n const hasItems = items.length > 0;\n const hasAuthError = items.some(item => item.error === 'invalid-api-key');\n\n if (hasAuthError) {\n this.setGlobalError(this.labels.invalidApiKey);\n }\n\n if (this.rootElement) {\n this.rootElement.classList.toggle('is-uploading', isUploading);\n this.rootElement.classList.toggle('has-items', hasItems);\n }\n\n if (this.dropzone) {\n if (hasItems) {\n this.dropzone.style.display = 'none';\n } else {\n this.dropzone.style.display = 'flex';\n }\n }\n\n this.renderFileList(items);\n this.updateErrorBanner();\n this.renderSourceOptions(hasItems);\n this.updateModalTitle(items, isUploading);\n this.updateDuplicateBanners(duplicates);\n\n if (this.modalHeaderElement) {\n this.modalHeaderElement.style.display = hasItems ? '' : 'none';\n }\n if (this.modalPoweredElement) {\n this.modalPoweredElement.style.display = hasItems ? 'none' : '';\n }\n if (this.inlinePoweredElement) {\n this.inlinePoweredElement.style.display = hasItems ? 'none' : '';\n }\n\n if (this.triggerType === 'button' || this.triggerType === 'inline') {\n const completedCount = items.filter(item => item.status === 'completed').length;\n const allCompleted = hasItems && completedCount === items.length && completedCount > 0;\n\n if (this.modalFooterActions) {\n this.modalFooterActions.style.display = hasItems ? '' : 'none';\n }\n\n const uploadButton = this.modalUploadButton;\n const doneButton = this.modalDoneButton;\n const cancelButton = this.modalCancelButton;\n const clearButton = this.modalClearButton;\n const addMoreButton = this.modalAddMoreButton;\n\n const showUpload = hasItems && !isUploading && !allCompleted;\n const showAddMore = hasItems && !isUploading && !allCompleted;\n const showDone = hasItems && (isUploading || allCompleted);\n const showClear = hasItems && (isUploading || allCompleted);\n const showInlineCancel =\n this.triggerType === 'inline' && hasItems && !isUploading && !allCompleted;\n const showButtonCancel =\n this.triggerType === 'button' && !isUploading && (!allCompleted || !hasItems);\n const showCancel = showInlineCancel || showButtonCancel;\n\n if (uploadButton) {\n uploadButton.style.display = showUpload ? '' : 'none';\n uploadButton.toggleAttribute('disabled', !showUpload);\n }\n\n if (doneButton) {\n doneButton.style.display = showDone ? '' : 'none';\n doneButton.textContent = this.labels.done;\n doneButton.toggleAttribute('disabled', !showDone);\n }\n\n if (clearButton) {\n clearButton.style.display = showClear ? '' : 'none';\n clearButton.toggleAttribute('disabled', isUploading);\n }\n\n if (cancelButton) {\n cancelButton.style.display = showCancel ? '' : 'none';\n cancelButton.classList.toggle(\n 'is-fullwidth',\n this.triggerType === 'button' && !hasItems\n );\n }\n\n if (addMoreButton) {\n addMoreButton.style.display = showAddMore ? '' : 'none';\n addMoreButton.toggleAttribute('disabled', !showAddMore);\n }\n }\n }\n\n private renderFileList(items: UploadItem[]) {\n if (!this.fileList) return;\n this.fileList.innerHTML = '';\n if (items.length === 0) {\n this.fileList.style.display = 'none';\n this.fileList.classList.remove('is-grid');\n return;\n }\n\n const isGridLayout = this.fileLayout === 'grid';\n this.fileList.style.display = isGridLayout ? 'grid' : 'flex';\n this.fileList.classList.toggle('is-grid', isGridLayout);\n if (isGridLayout) {\n this.fileList.style.gridTemplateColumns = 'repeat(auto-fill, minmax(140px, 1fr))';\n this.fileList.style.gap = '1rem';\n } else {\n this.fileList.style.removeProperty('grid-template-columns');\n this.fileList.style.removeProperty('gap');\n }\n\n const isUploading = this.controller?.getState().isUploading ?? false;\n\n items.forEach(item => {\n const li = document.createElement('li');\n li.className = 'ar-file-item';\n li.classList.toggle('is-grid', isGridLayout);\n\n const isInvalidApiKeyError = item.error === 'invalid-api-key';\n\n if (item.status === 'uploading' || item.status === 'pending') li.classList.add('is-uploading');\n if (item.status === 'completed') li.classList.add('is-completed');\n if (item.status === 'error' && !isInvalidApiKeyError) li.classList.add('is-error');\n\n const header = document.createElement('div');\n header.className = 'ar-file-header';\n header.classList.toggle('is-grid', isGridLayout);\n\n const thumb = document.createElement('div');\n thumb.className = 'ar-file-thumb';\n thumb.classList.toggle('is-grid', isGridLayout);\n if (item.previewUrl) {\n const img = document.createElement('img');\n img.src = item.previewUrl;\n img.alt = item.file.name;\n thumb.appendChild(img);\n } else {\n thumb.textContent = item.file.name.charAt(0).toUpperCase();\n }\n\n if (item.status === 'completed') {\n const statusOverlay = document.createElement('div');\n statusOverlay.className = 'ar-thumb-status';\n const successIcon = resolveIcon(this.icons.success);\n if (successIcon) {\n statusOverlay.appendChild(successIcon);\n }\n thumb.appendChild(statusOverlay);\n } else if (item.status === 'error' && !isInvalidApiKeyError) {\n const statusOverlay = document.createElement('div');\n statusOverlay.className = 'ar-thumb-status is-error';\n const errorIcon = resolveIcon(this.icons.error);\n if (errorIcon) {\n statusOverlay.appendChild(errorIcon);\n }\n thumb.appendChild(statusOverlay);\n }\n\n const name = document.createElement('span');\n name.className = 'ar-file-name';\n name.textContent = item.file.name;\n if (isGridLayout && !this.showGridFileName) {\n name.style.display = 'none';\n } else {\n name.style.display = '';\n }\n\n const removeButton = document.createElement('button');\n removeButton.type = 'button';\n removeButton.className = 'ar-remove-button';\n const shouldShowRemove =\n (item.status === 'pending' ||\n (item.status === 'error' && isInvalidApiKeyError)) &&\n !isUploading;\n removeButton.disabled = !shouldShowRemove;\n removeButton.hidden = !shouldShowRemove;\n removeButton.style.display = shouldShowRemove ? 'inline-flex' : 'none';\n removeButton.classList.toggle('is-grid', isGridLayout);\n const removeIcon = resolveIcon(this.icons.remove);\n if (removeIcon) {\n removeButton.appendChild(removeIcon);\n }\n removeButton.addEventListener('click', () => {\n if (this.controller?.getState().isUploading) return;\n this.controller?.removeFile(item.id);\n });\n\n header.appendChild(thumb);\n header.appendChild(name);\n header.appendChild(removeButton);\n li.appendChild(header);\n\n const progressBorder = document.createElement('div');\n progressBorder.className = 'ar-progress-border';\n\n const progressFill = document.createElement('div');\n progressFill.className = 'ar-progress-fill';\n\n const isPendingStatus = item.status === 'pending';\n const isUploadingStatus = item.status === 'uploading';\n const isCompleteStatus = item.status === 'completed';\n const rawProgress = Math.max(0, Math.min(100, item.progress ?? 0));\n const calculatedTrain = !isCompleteStatus && rawProgress < 20;\n const shouldAnimateTrain = (isUploadingStatus || (isUploading && isPendingStatus)) && calculatedTrain;\n const isActive = shouldAnimateTrain || (rawProgress > 0 && !isCompleteStatus);\n const stateLabel = isCompleteStatus ? 'complete' : shouldAnimateTrain ? 'train' : rawProgress >= 20 ? 'progress' : 'idle';\n\n progressBorder.dataset.state = stateLabel;\n progressBorder.dataset.status = item.status;\n progressBorder.dataset.progress = rawProgress.toFixed(0);\n\n progressBorder.classList.toggle('is-active', isActive);\n progressBorder.classList.toggle('is-train', shouldAnimateTrain);\n progressBorder.classList.toggle('is-complete', isCompleteStatus);\n progressBorder.style.display = isCompleteStatus ? 'none' : '';\n\n progressFill.classList.toggle('is-train', shouldAnimateTrain);\n progressFill.classList.toggle('is-animating', shouldAnimateTrain);\n\n if (isCompleteStatus) {\n progressFill.style.width = '100%';\n } else if (shouldAnimateTrain) {\n progressFill.style.width = '100%';\n } else {\n const computedWidth = Math.max(rawProgress, 3);\n progressFill.style.width = `${Math.min(computedWidth, 100)}%`;\n }\n\n progressBorder.appendChild(progressFill);\n\n const metaRow = document.createElement('div');\n metaRow.className = 'ar-file-meta';\n\n if (item.status === 'completed' && item.error === 'duplicate') {\n const duplicateBadge = document.createElement('span');\n duplicateBadge.className = 'ar-status is-warning';\n duplicateBadge.appendChild(document.createTextNode(this.labels.duplicateFileError));\n metaRow.appendChild(duplicateBadge);\n }\n\n li.appendChild(progressBorder);\n if (metaRow.childNodes.length > 0) {\n li.appendChild(metaRow);\n }\n\n this.fileList?.appendChild(li);\n });\n }\n\n private renderSourceOptions(hasItems: boolean) {\n // Filter out disabled sources - only show enabled ones\n const enabledSources = this.sourceOptions.filter(option => !option.disabled);\n const hasSourcesConfigured = enabledSources.length > 0;\n\n const renderChoiceList = (container: HTMLElement) => {\n container.innerHTML = '';\n if (!hasSourcesConfigured) {\n container.style.display = 'none';\n container.classList.remove('ar-source-list--choices');\n return;\n }\n\n container.style.display = hasItems ? 'none' : 'flex';\n container.classList.toggle('ar-source-list--choices', !hasItems);\n if (hasItems) return;\n\n // Only render enabled sources\n enabledSources.forEach(option => {\n const button = document.createElement('button');\n button.type = 'button';\n button.className = 'ar-source-option';\n\n const icon = resolveIcon(option.icon ?? this.icons.upload);\n if (icon) {\n const iconWrapper = document.createElement('span');\n iconWrapper.className = 'ar-source-option-icon';\n iconWrapper.appendChild(icon);\n button.appendChild(iconWrapper);\n }\n\n const label = document.createElement('span');\n label.className = 'ar-source-option-label';\n label.textContent = option.label;\n button.appendChild(label);\n\n button.addEventListener('click', () => this.handleSourceOption(option));\n container.appendChild(button);\n });\n };\n\n this.sourceLists.forEach(container => {\n renderChoiceList(container);\n });\n\n if (this.modalSourceContainer) {\n this.modalSourceContainer.classList.toggle('is-visible', hasSourcesConfigured && !hasItems);\n this.modalSourceContainer.style.display = hasSourcesConfigured ? '' : 'none';\n this.modalSourceContainer.innerHTML = '';\n }\n if (this.actionsSourceContainer) {\n this.actionsSourceContainer.classList.toggle('is-visible', hasSourcesConfigured && !hasItems);\n this.actionsSourceContainer.style.display = hasSourcesConfigured ? '' : 'none';\n this.actionsSourceContainer.innerHTML = '';\n }\n\n // Add class to modal body and inline upload when sources are empty in inline mode\n if (this.triggerType === 'inline') {\n if (this.modalBody) {\n this.modalBody.classList.toggle('ar-modal-body--no-sources', !hasSourcesConfigured);\n }\n if (this.inlineUpload) {\n this.inlineUpload.classList.toggle('ar-inline-upload--no-sources', !hasSourcesConfigured);\n }\n }\n }\n\n private updateModalTitle(items: UploadItem[], isUploading: boolean) {\n if (!this.modalTitleElement) return;\n if (items.length === 0) {\n this.modalTitleElement.textContent = isUploading\n ? this.labels.uploading\n : this.labels.title;\n this.modalTitleElement.classList.remove('is-dynamic', 'is-success');\n return;\n }\n\n const total = items.length;\n const modalTitle = this.modalTitleElement;\n\n const suffix = total === 1 ? 'file' : 'files';\n const completedCount = items.filter(item => item.status === 'completed').length;\n\n modalTitle.classList.add('is-dynamic');\n modalTitle.classList.toggle('is-success', completedCount === total);\n\n if (isUploading) {\n modalTitle.textContent = `Uploading ${completedCount}/${total} ${suffix}`;\n return;\n }\n\n if (completedCount === total) {\n modalTitle.textContent = `${total} ${suffix} uploaded`;\n return;\n }\n\n modalTitle.textContent = `${total} ${suffix} ready`;\n }\n\n private updateDuplicateBanners(duplicates: string[]) {\n const hasDuplicates = duplicates.length > 0;\n const prefix =\n duplicates.length === 1\n ? this.labels.duplicateFileExists\n : this.labels.duplicateFilesExist;\n const message = hasDuplicates\n ? `${prefix} ${duplicates.join(', ')}`\n : '';\n\n this.duplicateBanners.forEach(banner => {\n banner.hidden = !hasDuplicates;\n banner.textContent = message;\n });\n }\n\n private handleSourceOption(option: UploadSourceOption) {\n if (option.disabled) return;\n\n this.options.onSourceSelect?.(option);\n this.dispatchEvent(new CustomEvent('sourceselect', { detail: option }));\n\n if (option.kind === 'device' && !option.action) {\n this.openFileDialog();\n return;\n }\n\n if (option.action) {\n try {\n option.action();\n } catch (error) {\n console.error('[AutorenderUploader] Source action failed', error);\n }\n return;\n }\n\n console.warn('[AutorenderUploader] No handler configured for source option', option);\n }\n\n private applyThemeVariables() {\n const theme = (this.options.theme ?? {}) as ThemeOptions;\n const borderRadius = theme.borderRadius;\n const accentColor = theme.accentColor ?? DEFAULT_THEME.accentColor;\n const dropzoneBackground = theme.dropzoneBackground ?? DEFAULT_THEME.dropzoneBackground;\n const dropzoneBorder = theme.dropzoneBorder ?? DEFAULT_THEME.dropzoneBorder;\n const fontFamily = theme.fontFamily;\n\n if (borderRadius !== undefined) {\n this.style.setProperty(\n '--ar-radius',\n typeof borderRadius === 'number' ? `${borderRadius}px` : String(borderRadius)\n );\n } else {\n this.style.removeProperty('--ar-radius');\n }\n this.style.setProperty('--ar-color-accent', accentColor);\n\n if (dropzoneBackground) {\n this.style.setProperty('--ar-dropzone-bg', dropzoneBackground);\n }\n if (dropzoneBorder) {\n this.style.setProperty('--ar-dropzone-border', dropzoneBorder);\n }\n if (fontFamily) {\n this.style.setProperty('--ar-font-family', fontFamily);\n }\n\n const appearance = theme.appearance ?? DEFAULT_THEME.appearance;\n let resolvedAppearance = appearance;\n if (appearance === 'system' && typeof window !== 'undefined') {\n resolvedAppearance = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n }\n this.setAttribute('data-theme', resolvedAppearance);\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'autorender-uploader': AutorenderUploaderElement;\n }\n}"],"mappings":"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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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","names":["item","message"]}
@@ -0,0 +1,217 @@
1
+ type UploadStatus = 'pending' | 'ready' | 'uploading' | 'completed' | 'error';
2
+ interface UploadItem {
3
+ id: string;
4
+ file: File;
5
+ relativePath?: string;
6
+ folderPath: string;
7
+ folderNo?: string;
8
+ status: UploadStatus;
9
+ progress: number;
10
+ previewUrl?: string;
11
+ error?: string;
12
+ uploadedAt?: Date;
13
+ response?: UploadedFileResponse;
14
+ }
15
+ interface UploadedFileResponse {
16
+ file_no: string;
17
+ name: string;
18
+ url: string;
19
+ file_size: number;
20
+ folder_no?: string;
21
+ path?: string;
22
+ width?: number;
23
+ height?: number;
24
+ format?: string;
25
+ }
26
+ interface ThemeOptions {
27
+ appearance?: 'light' | 'dark' | 'system';
28
+ accentColor?: string;
29
+ borderRadius?: number;
30
+ fontFamily?: string;
31
+ dropzoneBackground?: string;
32
+ dropzoneBorder?: string;
33
+ }
34
+ type IconRenderer = string | HTMLElement | (() => string | HTMLElement);
35
+ interface IconSet {
36
+ upload?: IconRenderer;
37
+ success?: IconRenderer;
38
+ error?: IconRenderer;
39
+ remove?: IconRenderer;
40
+ close?: IconRenderer;
41
+ }
42
+ interface LabelSet {
43
+ title?: string;
44
+ description?: string;
45
+ selectButton?: string;
46
+ selectFolderButton?: string;
47
+ uploadButton?: string;
48
+ uploading?: string;
49
+ uploadComplete?: string;
50
+ uploadFailed?: string;
51
+ retry?: string;
52
+ remove?: string;
53
+ addMore?: string;
54
+ done?: string;
55
+ clear?: string;
56
+ cancel?: string;
57
+ dropzoneTitle?: string;
58
+ duplicateFileExists?: string;
59
+ duplicateFilesExist?: string;
60
+ duplicateFileError?: string;
61
+ invalidApiKey?: string;
62
+ }
63
+ interface UploaderClassNames {
64
+ root?: string;
65
+ triggerButton?: string;
66
+ dropzone?: string;
67
+ uploadButton?: string;
68
+ fileList?: string;
69
+ modal?: string;
70
+ summary?: string;
71
+ header?: string;
72
+ }
73
+ interface UploadSourceOption {
74
+ id: string;
75
+ label: string;
76
+ icon?: IconRenderer;
77
+ kind?: 'device' | 'camera' | 'facebook' | 'google-drive' | (string & {});
78
+ action?: () => void;
79
+ disabled?: boolean;
80
+ }
81
+ interface UploadSettings {
82
+ pretransformations?: string;
83
+ tags?: string[];
84
+ is_unique_suffix_name?: boolean;
85
+ }
86
+ interface CreateUploaderOptions {
87
+ apiKey: string;
88
+ target: string | HTMLElement;
89
+ width?: string | number;
90
+ folderPath?: string;
91
+ autoUpload?: boolean;
92
+ allowMultiple?: boolean;
93
+ accept?: string[];
94
+ chunkSize?: number;
95
+ parallelUploads?: number;
96
+ type?: 'button' | 'inline';
97
+ theme?: 'light' | 'dark' | 'system';
98
+ classNames?: UploaderClassNames;
99
+ sources?: string | string[];
100
+ fileLayout?: 'list' | 'grid';
101
+ showGridFileName?: boolean;
102
+ labels?: LabelSet;
103
+ uploadSettings?: UploadSettings;
104
+ onSourceSelect?: (source: UploadSourceOption) => void;
105
+ onProgress?: (progress: number, items: UploadItem[]) => void;
106
+ onFileProgress?: (item: UploadItem) => void;
107
+ onError?: (error: Error, context?: unknown) => void;
108
+ onSuccess?: (payload: {
109
+ files: UploadedFileResponse[];
110
+ items: UploadItem[];
111
+ }) => void;
112
+ }
113
+ interface UploaderInstance {
114
+ openFileDialog: () => void;
115
+ startUpload: () => Promise<void>;
116
+ reset: () => void;
117
+ destroy: () => void;
118
+ updateOptions: (options: Partial<CreateUploaderOptions>) => void;
119
+ getState: () => {
120
+ items: UploadItem[];
121
+ isUploading: boolean;
122
+ progress: number;
123
+ duplicates: string[];
124
+ };
125
+ }
126
+ interface PresignPayload {
127
+ folder_no?: string;
128
+ path?: string;
129
+ files: Array<{
130
+ name: string;
131
+ contentType: string;
132
+ size: number;
133
+ }>;
134
+ }
135
+ interface CompleteUploadPayload {
136
+ uploaded: Array<{
137
+ file_no: string;
138
+ key: string;
139
+ name: string;
140
+ size: number;
141
+ contentType: string;
142
+ folder_no?: string;
143
+ }>;
144
+ }
145
+ interface ApiFolderRequest {
146
+ name: string;
147
+ parent_folder_no?: string;
148
+ }
149
+ interface PresignedFile {
150
+ file_no: string;
151
+ key: string;
152
+ uploadUrl: string;
153
+ expiresIn: number;
154
+ folder_no?: string;
155
+ }
156
+ interface PresignResponse {
157
+ presigned: PresignedFile[];
158
+ duplicates?: string[];
159
+ }
160
+ interface CompleteUploadResponse {
161
+ files: UploadedFileResponse[];
162
+ }
163
+ interface UploadInitRequest {
164
+ fileName: string;
165
+ fileSize: number;
166
+ mimeType: string;
167
+ folderNo?: string;
168
+ path?: string;
169
+ settings?: UploadSettings;
170
+ }
171
+ interface UploadInitResponse {
172
+ success: boolean;
173
+ uploadToken: string;
174
+ uploadUrl: string;
175
+ destKey: string;
176
+ uploadId: string;
177
+ fileName: string;
178
+ fileSize: number;
179
+ mimeType: string;
180
+ tagsRaw: string[];
181
+ transformString: string;
182
+ }
183
+ interface AppRunnerResponse {
184
+ ok: boolean;
185
+ workspaceId: string;
186
+ key: string;
187
+ size: number;
188
+ width?: number;
189
+ height?: number;
190
+ format: string;
191
+ errorCode?: string;
192
+ message?: string;
193
+ }
194
+ interface CompleteUploadRequest {
195
+ uploadId: string;
196
+ appRunnerResponse: AppRunnerResponse;
197
+ }
198
+ interface CompleteUploadResponseNew {
199
+ success: boolean;
200
+ isDuplicate?: boolean;
201
+ file_no: string;
202
+ name: string;
203
+ url: string;
204
+ file_size: number;
205
+ format?: string;
206
+ width?: number;
207
+ height?: number;
208
+ created_at: Date;
209
+ path: string;
210
+ workspace_no: string;
211
+ }
212
+
213
+ declare function createUploader(options: CreateUploaderOptions): UploaderInstance;
214
+
215
+ declare function registerAutorenderUploaderElement(): void;
216
+
217
+ export { type ApiFolderRequest, type AppRunnerResponse, type CompleteUploadPayload, type CompleteUploadRequest, type CompleteUploadResponse, type CompleteUploadResponseNew, type CreateUploaderOptions, type IconRenderer, type IconSet, type LabelSet, type PresignPayload, type PresignResponse, type PresignedFile, type ThemeOptions, type UploadInitRequest, type UploadInitResponse, type UploadItem, type UploadSettings, type UploadSourceOption, type UploadStatus, type UploadedFileResponse, type UploaderClassNames, type UploaderInstance, createUploader, registerAutorenderUploaderElement };