uploaderkit 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +16 -0
  3. package/README.es.md +1140 -0
  4. package/README.md +1135 -0
  5. package/dist/FileViewer-ChTf7-uY.d.cts +49 -0
  6. package/dist/FileViewer-nuD-GEdJ.d.ts +49 -0
  7. package/dist/adapters/gcs.cjs +83 -0
  8. package/dist/adapters/gcs.cjs.map +1 -0
  9. package/dist/adapters/gcs.d.cts +31 -0
  10. package/dist/adapters/gcs.d.ts +31 -0
  11. package/dist/adapters/gcs.js +81 -0
  12. package/dist/adapters/gcs.js.map +1 -0
  13. package/dist/adapters/memory.cjs +27 -0
  14. package/dist/adapters/memory.cjs.map +1 -0
  15. package/dist/adapters/memory.d.cts +18 -0
  16. package/dist/adapters/memory.d.ts +18 -0
  17. package/dist/adapters/memory.js +25 -0
  18. package/dist/adapters/memory.js.map +1 -0
  19. package/dist/adapters/s3.cjs +75 -0
  20. package/dist/adapters/s3.cjs.map +1 -0
  21. package/dist/adapters/s3.d.cts +27 -0
  22. package/dist/adapters/s3.d.ts +27 -0
  23. package/dist/adapters/s3.js +73 -0
  24. package/dist/adapters/s3.js.map +1 -0
  25. package/dist/chunk-3FI44IOW.js +150 -0
  26. package/dist/chunk-3FI44IOW.js.map +1 -0
  27. package/dist/chunk-H7BRW5IY.js +308 -0
  28. package/dist/chunk-H7BRW5IY.js.map +1 -0
  29. package/dist/chunk-PDKAF4GX.js +707 -0
  30. package/dist/chunk-PDKAF4GX.js.map +1 -0
  31. package/dist/chunk-PTEX7F4R.js +309 -0
  32. package/dist/chunk-PTEX7F4R.js.map +1 -0
  33. package/dist/chunk-T5YZG6JW.js +511 -0
  34. package/dist/chunk-T5YZG6JW.js.map +1 -0
  35. package/dist/index.cjs +220 -27
  36. package/dist/index.cjs.map +1 -1
  37. package/dist/index.d.cts +57 -170
  38. package/dist/index.d.ts +57 -170
  39. package/dist/index.js +1 -324
  40. package/dist/index.js.map +1 -1
  41. package/dist/presets.cjs +1665 -0
  42. package/dist/presets.cjs.map +1 -0
  43. package/dist/presets.d.cts +100 -0
  44. package/dist/presets.d.ts +100 -0
  45. package/dist/presets.js +405 -0
  46. package/dist/presets.js.map +1 -0
  47. package/dist/react.cjs +981 -0
  48. package/dist/react.cjs.map +1 -0
  49. package/dist/react.d.cts +106 -0
  50. package/dist/react.d.ts +106 -0
  51. package/dist/react.js +5 -0
  52. package/dist/react.js.map +1 -0
  53. package/dist/server/express.cjs +179 -0
  54. package/dist/server/express.cjs.map +1 -0
  55. package/dist/server/express.d.cts +64 -0
  56. package/dist/server/express.d.ts +64 -0
  57. package/dist/server/express.js +111 -0
  58. package/dist/server/express.js.map +1 -0
  59. package/dist/server/next.cjs +165 -0
  60. package/dist/server/next.cjs.map +1 -0
  61. package/dist/server/next.d.cts +38 -0
  62. package/dist/server/next.d.ts +38 -0
  63. package/dist/server/next.js +107 -0
  64. package/dist/server/next.js.map +1 -0
  65. package/dist/server.cjs +550 -0
  66. package/dist/server.cjs.map +1 -0
  67. package/dist/server.d.cts +19 -0
  68. package/dist/server.d.ts +19 -0
  69. package/dist/server.js +80 -0
  70. package/dist/server.js.map +1 -0
  71. package/dist/storage-CYkSHWZX.d.cts +133 -0
  72. package/dist/storage-Qc9epG0G.d.ts +133 -0
  73. package/dist/types-BSlJJwti.d.cts +341 -0
  74. package/dist/types-BSlJJwti.d.ts +341 -0
  75. package/dist/ui.cjs +2325 -0
  76. package/dist/ui.cjs.map +1 -0
  77. package/dist/ui.d.cts +331 -0
  78. package/dist/ui.d.ts +331 -0
  79. package/dist/ui.js +749 -0
  80. package/dist/ui.js.map +1 -0
  81. package/dist/useSlottedUploader-BzT5jV8c.d.cts +139 -0
  82. package/dist/useSlottedUploader-IkG5RhEO.d.ts +139 -0
  83. package/dist/useUploader-BiBdS-7y.d.cts +117 -0
  84. package/dist/useUploader-CQHpj_oI.d.ts +117 -0
  85. package/package.json +189 -3
  86. package/tailwind.css +80 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/labels.ts","../src/react/UploaderProvider.tsx","../src/ui/cn.ts","../src/ui/overlayStack.ts","../src/ui/scrollLock.ts","../src/ui/useFocusTrap.ts","../src/ui/useOverlayTransition.ts","../src/ui/ConfirmDialog.tsx","../src/ui/Kbd.tsx","../src/ui/useCoarsePointer.ts","../src/warn.ts","../src/ui/useShortcut.ts","../src/ui/Dropzone.tsx","../src/constants.ts","../src/file.ts","../src/ui/FileTypeBadge.tsx","../src/ui/ProgressBar.tsx","../src/ui/FileItem.tsx","../src/ui/icons.tsx","../src/ui/FileViewer.tsx","../src/react/compressImage.ts","../src/react/slots.ts","../src/validation.ts","../src/scopes.ts","../src/react/useUploader.ts","../src/react/useSlottedUploader.ts","../src/ui/SlotRow.tsx","../src/ui/useFileViewer.ts","../src/ui/SlottedUploader.tsx","../src/ui/StoredFileItem.tsx","../src/ui/Uploader.tsx"],"names":["createContext","useMemo","jsx","useContext","active","useRef","useEffect","useState","createPortal","jsxs","useCallback","Fragment"],"mappings":"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","file":"ui.cjs","sourcesContent":["/**\n * Every user-facing string the package renders, so no copy is hardcoded\n * inside a component and apps translate or reword without forking.\n *\n * English is the default so the kit ships globalized; `ES_LABELS` ships for\n * Spanish apps, selected once through `UploaderProvider language='es'`. Hooks\n * take `labels` in their options, components as a prop — always a `Partial`,\n * merged over the provider's base.\n */\nexport type UploaderLabels = {\n\t/** Prompt inside the single dropzone of `Uploader` (fine pointers). */\n\tdropPrompt: string\n\t/** Same zone on a touch device, where dragging barely exists. */\n\ttapPrompt: string\n\t/** Prompt inside the bulk dropzone of `SlottedUploader` (fine pointers). */\n\tbulkDropPrompt: string\n\t/** Same bulk zone on a touch device. */\n\tbulkTapPrompt: string\n\t/** Button that fires the batch when `uploadOn` is `'manual'`. */\n\tuploadAll: string\n\t/** Row action: preview a file. */\n\tview: string\n\t/** Row action: forget a file. */\n\tremove: string\n\t/** Row action: abort an in-flight upload. */\n\tcancel: string\n\t/** Suffix on a row the server confirmed. */\n\tready: string\n\t/**\n\t * Suffix on a row holding a picked file that has NOT been sent yet.\n\t * Distinct from {@link UploaderLabels.ready}, which means the server\n\t * confirmed it — two states, two strings.\n\t */\n\tstaged: string\n\t/** Slot action when the position is empty. */\n\tupload: string\n\t/** Slot action when the position is filled. */\n\treplace: string\n\t/** Pill shown while a file hovers over a filled slot row. */\n\tdropToReplace: string\n\t/** Viewer: aria-label of the previous-image arrow. */\n\tprevious: string\n\t/** Viewer: aria-label of the next-image arrow. */\n\tnext: string\n\t/** Fallback when a strategy rejects without a message. */\n\tuploadFailed: string\n\t/** The request never reached the server — offline, DNS, CORS preflight. */\n\tuploadNetworkFailed: string\n\t/** Message when the DELETE transport refused or failed. */\n\tremoveFailed: string\n\t/** A stored file could not be fetched for preview or for bytes. */\n\treadFailed: string\n\t/** A batch past `maxFiles`. Receives the cap. */\n\tmaxFilesReached: (max: number) => string\n\t/** A file picked for a slot whose extension the slot rejects. */\n\tslotFormatNotAllowed: (slotLabel: string, extensions: string[]) => string\n\t/** A bulk-dropped file no slot matched. */\n\tfileWithoutSlot: (fileName: string) => string\n\t/** Viewer: while the URL resolves. */\n\tviewerLoading: string\n\t/** Viewer: the URL could not be resolved (expired signature, network). */\n\tviewerError: string\n\t/** Second line of the error panel — what the reader can do about it. */\n\tviewerErrorHint: string\n\t/** Viewer: button that retries the resolution. */\n\tviewerRetry: string\n\t/** Viewer: open the file in a browser tab. */\n\topenInTab: string\n\t/** Header action; the long `download` names a file, this labels a button. */\n\tdownloadShort: string\n\t/** Viewer: close button. */\n\tclose: string\n\t/** Viewer: formats without an inline preview. */\n\tnoPreview: string\n\t/** Viewer: download button. Receives the file name. */\n\tdownload: (fileName: string) => string\n\t/** Viewer: fallback title when the file carries no name. */\n\tfilePreview: string\n\t/** Confirm dialog: affirmative button. */\n\tconfirm: string\n\t/** Confirm dialog heading before forgetting a file. */\n\tconfirmRemoveTitle: string\n\t/** Confirm dialog body before forgetting. Receives the file name. */\n\tconfirmRemoveMessage: (fileName: string) => string\n\t/** Confirm dialog heading before replacing a slot's file. */\n\tconfirmReplaceTitle: string\n\t/** Confirm dialog body before replacing. Receives current and incoming names. */\n\tconfirmReplaceMessage: (current: string, incoming: string) => string\n\t/** `DropAnywhereOverlay` heading while a drag is over the window. */\n\tdropAnywhereTitle: string\n\t/** `DropAnywhereOverlay` second line. */\n\tdropAnywhereHint: string\n\t/** `AvatarUploader`: hover label and aria-label of the picture. */\n\tavatarChange: string\n\t/** `AvatarUploader`: overlay while a file hovers the picture. */\n\tavatarDropHere: string\n\t/** `AvatarUploader`: the remove link under the picture. */\n\tavatarRemove: string\n\t/** `GalleryUploader`: caption of the add tile. */\n\tgalleryAdd: string\n\n\t// Validation — `validateFile` and everything that calls it. These run on\n\t// BOTH sides: the browser shows them, the server answers them as JSON.\n\t/** A name the extension check cannot read at all. */\n\tfileHasNoExtension: string\n\t/** The extension is not on the scope's list. Receives that list. */\n\tformatNotAllowed: (extensions: string[]) => string\n\t/** Zero bytes — a failed drag, a cancelled save. */\n\tfileIsEmpty: string\n\t/** Over the scope ceiling. Receives both sizes already formatted. */\n\tfileTooLarge: (size: string, max: string) => string\n\t/** Fewer bytes than the signature needs: a truncated transfer. */\n\tfileIncomplete: string\n\t/** The leading bytes contradict the extension — renamed, or corrupt. */\n\tcontentDoesNotMatchExtension: string\n\n\t// Server — the HTTP surface. `createStorage` and both framework adapters\n\t// resolve the same object, so one `labels` wires the whole round trip.\n\t/** 400: a route parameter or body field the handler needs is missing. */\n\trequestIncomplete: string\n\t/** 401: `getUser` answered null. */\n\tunauthorized: string\n\t/** 400: an upload arrived with no file part. */\n\tfileRequired: string\n\t/** 404: the URL named a scope the registry does not declare. */\n\tunknownScope: string\n\t/** 500: the catch-all when a handler throws something unrecognized. */\n\tprocessingFailed: string\n\t/** Download name for a key that ends in nothing usable. */\n\tunnamedFile: string\n}\n\n/** Spanish copy — select it once: `<UploaderProvider language='es'>`. */\nexport const ES_LABELS: UploaderLabels = {\n\tdropPrompt: 'Selecciona un archivo o arrástralo aquí',\n\ttapPrompt: 'Toca para elegir un archivo',\n\tbulkDropPrompt: 'Arrastra varios archivos — cada uno cae en su documento',\n\tbulkTapPrompt: 'Toca para agregar varios archivos',\n\tuploadAll: 'Subir archivos',\n\tview: 'Ver',\n\tremove: 'Quitar',\n\tcancel: 'Cancelar',\n\tready: 'Listo',\n\tstaged: 'Listo para subir',\n\tupload: 'Subir',\n\treplace: 'Reemplazar',\n\tdropToReplace: 'Suelta para reemplazar',\n\tprevious: 'Anterior',\n\tnext: 'Siguiente',\n\tuploadFailed: 'No se pudo subir el archivo',\n\tuploadNetworkFailed: 'No se pudo subir el archivo. Revisa tu conexión',\n\tremoveFailed: 'No se pudo borrar el archivo del almacenamiento',\n\treadFailed: 'No se pudo cargar el archivo',\n\tmaxFilesReached: max => `Máximo ${max} archivo(s)`,\n\tslotFormatNotAllowed: (slotLabel, extensions) =>\n\t\t`${slotLabel}: formato no permitido. Se aceptan: ${extensions.join(', ')}`,\n\tfileWithoutSlot: fileName =>\n\t\t`\"${fileName}\" no corresponde a ningún documento`,\n\tviewerLoading: 'Cargando…',\n\tviewerError: 'No se pudo cargar la vista previa',\n\tviewerErrorHint:\n\t\t'El archivo puede haberse movido o el enlace expiró. Puedes reintentar o descargarlo.',\n\tviewerRetry: 'Reintentar',\n\topenInTab: 'Abrir en pestaña',\n\tdownloadShort: 'Descargar',\n\tclose: 'Cerrar',\n\tnoPreview: 'Este formato no tiene vista previa',\n\tdownload: fileName => `Descargar ${fileName}`,\n\tfilePreview: 'Archivo',\n\tconfirm: 'Confirmar',\n\tconfirmRemoveTitle: 'Quitar archivo',\n\tconfirmRemoveMessage: fileName =>\n\t\t`¿Quitar \"${fileName}\"? Podrás subir otro después.`,\n\tconfirmReplaceTitle: 'Reemplazar archivo',\n\tconfirmReplaceMessage: (current, incoming) =>\n\t\t`¿Reemplazar \"${current}\" por \"${incoming}\"?`,\n\tdropAnywhereTitle: 'Suelta los archivos aquí',\n\tdropAnywhereHint: 'Cualquier lugar de la pantalla cuenta',\n\tavatarChange: 'Cambiar foto',\n\tavatarDropHere: 'Suelta aquí',\n\tavatarRemove: 'Quitar foto',\n\tgalleryAdd: 'Agregar',\n\n\tfileHasNoExtension: 'El archivo no tiene extensión',\n\tformatNotAllowed: extensions =>\n\t\t`Formato no permitido. Se aceptan: ${extensions.join(', ')}`,\n\tfileIsEmpty: 'El archivo está vacío',\n\tfileTooLarge: (size, max) => `El archivo pesa ${size} y el máximo es ${max}`,\n\tfileIncomplete: 'El archivo está incompleto',\n\tcontentDoesNotMatchExtension:\n\t\t'El contenido del archivo no corresponde a su extensión',\n\n\trequestIncomplete: 'Solicitud incompleta',\n\tunauthorized: 'No autorizado',\n\tfileRequired: 'Archivo requerido',\n\tunknownScope: 'Destino de archivo no válido',\n\tprocessingFailed: 'No se pudo procesar el archivo',\n\tunnamedFile: 'archivo',\n}\n\n/** English copy — the package default, so the kit ships globalized. */\nexport const DEFAULT_LABELS: UploaderLabels = {\n\tdropPrompt: 'Choose a file or drag it here',\n\ttapPrompt: 'Tap to choose a file',\n\tbulkDropPrompt: 'Drop several files — each lands on its document',\n\tbulkTapPrompt: 'Tap to add several files',\n\tuploadAll: 'Upload files',\n\tview: 'View',\n\tremove: 'Remove',\n\tcancel: 'Cancel',\n\tready: 'Done',\n\tstaged: 'Ready to upload',\n\tupload: 'Upload',\n\treplace: 'Replace',\n\tdropToReplace: 'Drop to replace',\n\tprevious: 'Previous',\n\tnext: 'Next',\n\tuploadFailed: 'The file could not be uploaded',\n\tuploadNetworkFailed: 'The file could not be uploaded. Check your connection',\n\tremoveFailed: 'The file could not be removed from storage',\n\treadFailed: 'The file could not be loaded',\n\tmaxFilesReached: max => `At most ${max} file(s)`,\n\tslotFormatNotAllowed: (slotLabel, extensions) =>\n\t\t`${slotLabel}: format not allowed. Accepted: ${extensions.join(', ')}`,\n\tfileWithoutSlot: fileName => `\"${fileName}\" does not match any document`,\n\tviewerLoading: 'Loading…',\n\tviewerError: 'The preview could not be loaded',\n\tviewerErrorHint:\n\t\t'The file may have moved or the link expired. You can retry or download it.',\n\tviewerRetry: 'Retry',\n\topenInTab: 'Open in tab',\n\tdownloadShort: 'Download',\n\tclose: 'Close',\n\tnoPreview: 'This format has no preview',\n\tdownload: fileName => `Download ${fileName}`,\n\tfilePreview: 'File',\n\tconfirm: 'Confirm',\n\tconfirmRemoveTitle: 'Remove file',\n\tconfirmRemoveMessage: fileName =>\n\t\t`Remove \"${fileName}\"? You can upload another one later.`,\n\tconfirmReplaceTitle: 'Replace file',\n\tconfirmReplaceMessage: (current, incoming) =>\n\t\t`Replace \"${current}\" with \"${incoming}\"?`,\n\tdropAnywhereTitle: 'Drop the files here',\n\tdropAnywhereHint: 'Anywhere on the screen counts',\n\tavatarChange: 'Change photo',\n\tavatarDropHere: 'Drop here',\n\tavatarRemove: 'Remove photo',\n\tgalleryAdd: 'Add',\n\n\tfileHasNoExtension: 'The file has no extension',\n\tformatNotAllowed: extensions =>\n\t\t`Format not allowed. Accepted: ${extensions.join(', ')}`,\n\tfileIsEmpty: 'The file is empty',\n\tfileTooLarge: (size, max) =>\n\t\t`The file weighs ${size} and the maximum is ${max}`,\n\tfileIncomplete: 'The file is incomplete',\n\tcontentDoesNotMatchExtension: 'The file contents do not match its extension',\n\n\trequestIncomplete: 'Incomplete request',\n\tunauthorized: 'Unauthorized',\n\tfileRequired: 'A file is required',\n\tunknownScope: 'Unknown file destination',\n\tprocessingFailed: 'The file could not be processed',\n\tunnamedFile: 'file',\n}\n\n/** The merge every entry point runs: partial overrides over the default. */\nexport const resolveLabels = (\n\tlabels?: Partial<UploaderLabels>,\n\tbase: UploaderLabels = DEFAULT_LABELS\n): UploaderLabels => (labels ? { ...base, ...labels } : base)\n\n/**\n * @deprecated English IS {@link DEFAULT_LABELS} now. A shallow copy, kept so\n * 1.x consumers passing it keep working.\n */\nexport const EN_LABELS: UploaderLabels = { ...DEFAULT_LABELS }\n","import { createContext, type ReactNode, useContext, useMemo } from 'react'\n\nimport {\n\tDEFAULT_LABELS,\n\tES_LABELS,\n\tresolveLabels,\n\ttype UploaderLabels,\n} from '../labels'\n\nconst LabelsContext = createContext<UploaderLabels>(DEFAULT_LABELS)\n\n/** The two built-in copy sets. */\nexport type UploaderLanguage = 'en' | 'es'\n\nexport type UploaderProviderProps = {\n\tchildren: ReactNode\n\t/**\n\t * Which built-in copy set every uploader under it speaks. English is the\n\t * default so the kit ships globalized; a Spanish app opts in ONCE here\n\t * instead of passing `labels` to each component.\n\t * @defaultValue 'en'\n\t */\n\tlanguage?: UploaderLanguage\n\t/** Per-key overrides on top of the selected language. */\n\tlabels?: Partial<UploaderLabels>\n}\n\n/**\n * Optional app-root provider carrying the copy. Components work without it\n * (they fall back to {@link DEFAULT_LABELS}), and a per-component `labels`\n * prop still wins for one-off rewording.\n */\nexport const UploaderProvider = ({\n\tchildren,\n\tlanguage = 'en',\n\tlabels,\n}: UploaderProviderProps) => {\n\tconst value = useMemo(\n\t\t() => resolveLabels(labels, language === 'es' ? ES_LABELS : DEFAULT_LABELS),\n\t\t[language, labels]\n\t)\n\n\treturn (\n\t\t<LabelsContext.Provider value={value}>{children}</LabelsContext.Provider>\n\t)\n}\n\n/**\n * The active copy, merged: provider base ← per-call `overrides`. What every\n * component and hook in the package reads instead of `resolveLabels` directly,\n * so a single provider re-words all of them at once.\n */\nexport const useUploaderLabels = (\n\toverrides?: Partial<UploaderLabels>\n): UploaderLabels => {\n\tconst base = useContext(LabelsContext)\n\treturn useMemo(\n\t\t() => (overrides ? { ...base, ...overrides } : base),\n\t\t[base, overrides]\n\t)\n}\n","/** Minimal class joiner — the package has no runtime deps to spend on clsx. */\nexport const cn = (...values: (string | false | null | undefined)[]): string =>\n\tvalues.filter(Boolean).join(' ')\n","import { useEffect, useMemo, useRef } from 'react'\n\n/**\n * Which open overlay answers a dismiss key.\n *\n * `FileViewer` and `ConfirmDialog` both claim Escape on `window` in the\n * CAPTURE phase, so they beat a host app's own dialog (a typical Modal\n * listens on `document` in bubble). But two listeners on the same node\n * in the same phase both run — `stopPropagation` only stops other NODES — so\n * a confirm opened over the viewer would close both on one press.\n *\n * Ordering by registration would not help either: that is open order, and the\n * layer that must answer is the innermost, which opened last.\n *\n * Package-local on purpose: a design system that ships its own dismiss\n * stack keeps it, and neither has to depend on the other (invariant §4).\n */\nlet sequence = 0\nconst stack: number[] = []\n\nexport type OverlayLayer = {\n\t/** `true` while this layer is the innermost open one. */\n\tisTopmost: () => boolean\n}\n\n/** Joins the stack while `active`, and leaves it on close or unmount. */\nexport const useOverlayLayer = (active: boolean): OverlayLayer => {\n\tconst idRef = useRef(0)\n\tif (idRef.current === 0) idRef.current = ++sequence\n\n\tuseEffect(() => {\n\t\tif (!active) return\n\t\tconst id = idRef.current\n\t\tstack.push(id)\n\t\treturn () => {\n\t\t\tconst at = stack.lastIndexOf(id)\n\t\t\tif (at !== -1) stack.splice(at, 1)\n\t\t}\n\t}, [active])\n\n\treturn useMemo(\n\t\t() => ({ isTopmost: () => stack[stack.length - 1] === idRef.current }),\n\t\t[]\n\t)\n}\n","/**\n * Body scroll lock, reference counted across overlays AND across packages —\n * the state lives on `globalThis` so every copy converges on one counter.\n *\n * @see AGENTS.md §4 — the key and the shape are an invariant, not a detail\n */\ntype ScrollLockState = { count: number; saved: string }\n\nconst KEY = Symbol.for('uploaderkit.bodyScrollLock')\n\nconst state = (): ScrollLockState => {\n\tconst host = globalThis as { [KEY]?: ScrollLockState }\n\treturn (host[KEY] ??= { count: 0, saved: '' })\n}\n\nexport const lockBodyScroll = (): void => {\n\tconst lock = state()\n\tif (lock.count === 0) {\n\t\tlock.saved = document.body.style.overflow\n\t\tdocument.body.style.overflow = 'hidden'\n\t}\n\tlock.count += 1\n}\n\nexport const unlockBodyScroll = (): void => {\n\tconst lock = state()\n\t// An unbalanced unlock must be a no-op — decrementing past zero would\n\t// re-apply a stale saved value onto a page nobody locked.\n\tif (lock.count === 0) return\n\tlock.count -= 1\n\tif (lock.count === 0) document.body.style.overflow = lock.saved\n}\n","import { type RefObject, useEffect } from 'react'\n\nconst FOCUSABLE =\n\t'a[href],button:not([disabled]),textarea:not([disabled]),input:not([disabled]),select:not([disabled]),[tabindex]:not([tabindex=\"-1\"])'\n\n/**\n * Keeps `Tab` inside `ref` while `active`, focuses the panel (or its first\n * `[data-autofocus]`) on activation, and restores focus to whatever had it\n * before — the contract a modal owes the keyboard.\n */\nexport const useFocusTrap = (\n\tactive: boolean,\n\tref: RefObject<HTMLElement | null>\n): void => {\n\tuseEffect(() => {\n\t\tif (!active) return\n\t\tconst restoreTo = document.activeElement as HTMLElement | null\n\n\t\tconst panel = ref.current\n\t\tconst initial =\n\t\t\tpanel?.querySelector<HTMLElement>('[data-autofocus]') ?? panel\n\t\tinitial?.focus({ preventScroll: true })\n\n\t\tconst onKeyDown = (event: KeyboardEvent) => {\n\t\t\tif (event.key !== 'Tab' || !ref.current) return\n\t\t\tconst focusables = Array.from(\n\t\t\t\tref.current.querySelectorAll<HTMLElement>(FOCUSABLE)\n\t\t\t).filter(el => el.offsetParent !== null)\n\t\t\tif (focusables.length === 0) {\n\t\t\t\tevent.preventDefault()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst first = focusables[0]!\n\t\t\tconst last = focusables[focusables.length - 1]!\n\t\t\tif (event.shiftKey && document.activeElement === first) {\n\t\t\t\tevent.preventDefault()\n\t\t\t\tlast.focus()\n\t\t\t} else if (!event.shiftKey && document.activeElement === last) {\n\t\t\t\tevent.preventDefault()\n\t\t\t\tfirst.focus()\n\t\t\t}\n\t\t}\n\n\t\tdocument.addEventListener('keydown', onKeyDown)\n\t\treturn () => {\n\t\t\tdocument.removeEventListener('keydown', onKeyDown)\n\t\t\trestoreTo?.focus({ preventScroll: true })\n\t\t}\n\t}, [active, ref])\n}\n","import { useEffect, useRef, useState } from 'react'\n\n/** Kept in sync with the transition classes the overlays use. */\nconst OVERLAY_ANIMATION_MS = 200\n\nexport type OverlayTransition = {\n\t/** Render while `true` — spans the exit animation past `open = false`. */\n\tmounted: boolean\n\t/** Drives the transition classes: `false` on both edges of the animation. */\n\tentered: boolean\n}\n\n/**\n * The enter/exit choreography every overlay shares: render on open, flip\n * `entered` a frame later so the transition runs, keep rendering\n * `OVERLAY_ANIMATION_MS` past close so the exit is visible.\n *\n * @see AGENTS.md §3\n */\nexport const useOverlayTransition = (open: boolean): OverlayTransition => {\n\tconst [entered, setEntered] = useState(false)\n\tconst [exiting, setExiting] = useState(false)\n\tconst wasOpen = useRef(false)\n\n\tuseEffect(() => {\n\t\tif (open) {\n\t\t\twasOpen.current = true\n\t\t\tsetExiting(false)\n\t\t\tconst raf = requestAnimationFrame(() => setEntered(true))\n\t\t\treturn () => cancelAnimationFrame(raf)\n\t\t}\n\t\tsetEntered(false)\n\t\tif (!wasOpen.current) return\n\t\twasOpen.current = false\n\t\tsetExiting(true)\n\t\tconst timer = setTimeout(() => setExiting(false), OVERLAY_ANIMATION_MS)\n\t\treturn () => clearTimeout(timer)\n\t}, [open])\n\n\treturn { mounted: open || exiting, entered }\n}\n","import { type ReactNode, useEffect, useRef } from 'react'\nimport { createPortal } from 'react-dom'\n\nimport type { UploaderLabels } from '../labels'\nimport { useUploaderLabels } from '../react/UploaderProvider'\nimport { cn } from './cn'\nimport { useOverlayLayer } from './overlayStack'\nimport { lockBodyScroll, unlockBodyScroll } from './scrollLock'\nimport { useFocusTrap } from './useFocusTrap'\nimport { useOverlayTransition } from './useOverlayTransition'\n\nexport type ConfirmDialogProps = {\n\topen: boolean\n\ttitle: string\n\tmessage: ReactNode\n\t/** Tone of the affirmative button. @defaultValue 'danger' */\n\tvariant?: 'danger' | 'primary'\n\tconfirmLabel?: string\n\tcancelLabel?: string\n\tonConfirm: () => void\n\tonCancel: () => void\n\tlabels?: Partial<UploaderLabels>\n}\n\n/**\n * Second-step gate for destructive file actions — remove a stored file,\n * replace a slot. Focus lands on **cancel** so a stray Enter never destroys\n * anything, Escape and the backdrop cancel, and `Tab` stays inside. Exported\n * for app-level use around the uploaders' callbacks.\n */\nexport const ConfirmDialog = ({\n\topen,\n\ttitle,\n\tmessage,\n\tvariant = 'danger',\n\tconfirmLabel,\n\tcancelLabel,\n\tonConfirm,\n\tonCancel,\n\tlabels,\n}: ConfirmDialogProps) => {\n\tconst copy = useUploaderLabels(labels)\n\tconst panelRef = useRef<HTMLDivElement>(null)\n\tconst { mounted, entered } = useOverlayTransition(open)\n\tconst layer = useOverlayLayer(open)\n\tuseFocusTrap(open, panelRef)\n\n\tconst cancelRef = useRef(onCancel)\n\tcancelRef.current = onCancel\n\n\tuseEffect(() => {\n\t\tif (!open) return\n\t\tconst onKey = (event: KeyboardEvent) => {\n\t\t\tif (event.key === 'Escape') {\n\t\t\t\tif (!layer.isTopmost()) return\n\t\t\t\tevent.stopPropagation()\n\t\t\t\tcancelRef.current()\n\t\t\t}\n\t\t}\n\t\t// Capture phase: both overlays claim the key before any host dialog in\n\t\t// bubble. Which of the two answers is decided by the layer stack.\n\t\twindow.addEventListener('keydown', onKey, true)\n\t\tlockBodyScroll()\n\t\treturn () => {\n\t\t\twindow.removeEventListener('keydown', onKey, true)\n\t\t\tunlockBodyScroll()\n\t\t}\n\t}, [open, layer])\n\n\tif (!mounted) return null\n\n\treturn createPortal(\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'fixed inset-0 z-1000 flex items-end justify-center p-4 sm:items-center',\n\t\t\t\t!open && 'pointer-events-none'\n\t\t\t)}\n\t\t\tonClick={onCancel}\n\t\t>\n\t\t\t<div\n\t\t\t\taria-hidden\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'bg-ui-overlay fixed inset-0 transition-opacity duration-200 ease-out',\n\t\t\t\t\tentered ? 'opacity-100' : 'opacity-0'\n\t\t\t\t)}\n\t\t\t/>\n\t\t\t<div\n\t\t\t\tref={panelRef}\n\t\t\t\trole='alertdialog'\n\t\t\t\taria-modal='true'\n\t\t\t\taria-label={title}\n\t\t\t\ttabIndex={-1}\n\t\t\t\tonClick={event => event.stopPropagation()}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'bg-ui-surface rounded-ui-xl relative w-full max-w-md p-6 shadow-2xl outline-none',\n\t\t\t\t\t'transition duration-200 ease-out',\n\t\t\t\t\tentered\n\t\t\t\t\t\t? 'translate-y-0 scale-100 opacity-100'\n\t\t\t\t\t\t: 'translate-y-3 scale-[0.97] opacity-0'\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<div className='flex items-start gap-4'>\n\t\t\t\t\t<span\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'flex size-11 shrink-0 items-center justify-center rounded-full',\n\t\t\t\t\t\t\tvariant === 'danger' ? 'bg-ui-danger-soft' : 'bg-ui-primary-soft'\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\tviewBox='0 0 24 24'\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t'size-6',\n\t\t\t\t\t\t\t\tvariant === 'danger' ? 'text-ui-danger' : 'text-ui-primary'\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\tfill='none'\n\t\t\t\t\t\t\tstroke='currentColor'\n\t\t\t\t\t\t\tstrokeWidth='2'\n\t\t\t\t\t\t\tstrokeLinecap='round'\n\t\t\t\t\t\t\tstrokeLinejoin='round'\n\t\t\t\t\t\t\taria-hidden\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<path d='M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z' />\n\t\t\t\t\t\t\t<line x1='12' y1='9' x2='12' y2='13' />\n\t\t\t\t\t\t\t<line x1='12' y1='17' x2='12.01' y2='17' />\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t</span>\n\n\t\t\t\t\t<div className='min-w-0 flex-1'>\n\t\t\t\t\t\t<h2 className='text-ui-fg text-base font-semibold'>{title}</h2>\n\t\t\t\t\t\t<div className='text-ui-muted mt-1 text-sm'>{message}</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\n\t\t\t\t<div className='mt-6 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end'>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype='button'\n\t\t\t\t\t\tdata-autofocus\n\t\t\t\t\t\tonClick={onCancel}\n\t\t\t\t\t\tclassName='border-ui-border-strong text-ui-fg hover:bg-ui-surface-muted focus-visible:ring-ui-ring rounded-ui h-10 cursor-pointer border px-4 text-sm font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none sm:w-auto'\n\t\t\t\t\t>\n\t\t\t\t\t\t{cancelLabel ?? copy.cancel}\n\t\t\t\t\t</button>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype='button'\n\t\t\t\t\t\tonClick={onConfirm}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'focus-visible:ring-ui-ring rounded-ui h-10 cursor-pointer px-4 text-sm font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none sm:w-auto',\n\t\t\t\t\t\t\tvariant === 'danger'\n\t\t\t\t\t\t\t\t? 'bg-ui-danger text-ui-danger-fg hover:bg-ui-danger-hover'\n\t\t\t\t\t\t\t\t: 'bg-ui-primary text-ui-primary-fg hover:bg-ui-primary-hover'\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{confirmLabel ?? copy.confirm}\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>,\n\t\tdocument.body\n\t)\n}\n","import type { ReactNode } from 'react'\n\n/** The little key hint every shortcut announces itself with. */\nexport const Kbd = ({ children }: { children: ReactNode }) => (\n\t<kbd className='border-ui-border bg-ui-surface text-ui-muted rounded-md border px-1.5 py-0.5 font-sans text-[10px] font-medium shadow-sm'>\n\t\t{children}\n\t</kbd>\n)\n","import { useEffect, useState } from 'react'\n\n/**\n * `true` on touch-first devices (`pointer: coarse`), where drag-and-drop\n * barely exists and the zone should read as a tap target. SSR-safe: first\n * paint assumes a fine pointer and corrects in the effect.\n */\nexport const useCoarsePointer = (): boolean => {\n\tconst [coarse, setCoarse] = useState(false)\n\n\tuseEffect(() => {\n\t\tconst query = window.matchMedia('(pointer: coarse)')\n\t\tsetCoarse(query.matches)\n\t\tconst onChange = (event: MediaQueryListEvent) => setCoarse(event.matches)\n\t\tquery.addEventListener('change', onChange)\n\t\treturn () => query.removeEventListener('change', onChange)\n\t}, [])\n\n\treturn coarse\n}\n","const seen = new Set<string>()\n\n/**\n * Dev-only warning, once per `key` — for paths that run per render or per\n * file, where the same misconfiguration would otherwise print hundreds of\n * times. Same contract as listkit's `warnDev`.\n *\n * @see AGENTS.md §3.1 — this tier vs the `ScopeError` throw\n */\nexport const warnDev = (key: string, message: string): void => {\n\tif (process.env.NODE_ENV === 'production') return\n\tif (seen.has(key)) return\n\tseen.add(key)\n\tconsole.warn(`[uploaderkit] ${message}`)\n}\n","import { useEffect, useRef } from 'react'\n\nimport { warnDev } from '../warn'\n\ntype ShortcutSpec = {\n\tmod: boolean\n\tshift: boolean\n\talt: boolean\n\tkey: string\n}\n\n/** `'mod+u'` → ⌘U on mac, Ctrl+U elsewhere. `mod`, `shift`, `alt` + one key. */\nconst parseShortcut = (combo: string): ShortcutSpec => {\n\tconst parts = combo.toLowerCase().split('+')\n\treturn {\n\t\tmod: parts.includes('mod'),\n\t\tshift: parts.includes('shift'),\n\t\talt: parts.includes('alt'),\n\t\tkey: parts[parts.length - 1]!,\n\t}\n}\n\nconst IS_MAC =\n\ttypeof navigator !== 'undefined' && /mac/i.test(navigator.platform)\n\n/** Human hint for a combo: `'mod+u'` → `⌘U` / `Ctrl+U`. */\nexport const formatShortcut = (combo: string): string => {\n\tconst spec = parseShortcut(combo)\n\tconst key = spec.key.length === 1 ? spec.key.toUpperCase() : spec.key\n\tconst parts: string[] = []\n\tif (spec.mod) parts.push(IS_MAC ? '⌘' : 'Ctrl')\n\tif (spec.alt) parts.push(IS_MAC ? '⌥' : 'Alt')\n\tif (spec.shift) parts.push(IS_MAC ? '⇧' : 'Shift')\n\tparts.push(key)\n\treturn parts.join(IS_MAC ? '' : '+')\n}\n\n/** Combos currently bound, to catch two zones claiming the same keys. */\nconst active = new Map<string, number>()\n\n/**\n * Binds a global shortcut while mounted. Never fires from an input, textarea\n * or contenteditable — typing keeps priority — and warns in development when\n * two surfaces register the same combo at once, because only both firing or\n * an arbitrary winner can come out of that.\n */\nexport const useShortcut = (\n\tcombo: string | undefined,\n\thandler: () => void,\n\tdisabled = false\n): void => {\n\tconst handlerRef = useRef(handler)\n\thandlerRef.current = handler\n\n\tuseEffect(() => {\n\t\tif (!combo || disabled) return\n\t\tconst spec = parseShortcut(combo)\n\n\t\tactive.set(combo, (active.get(combo) ?? 0) + 1)\n\t\tif ((active.get(combo) ?? 0) > 1) {\n\t\t\twarnDev(\n\t\t\t\t`shortcut-collision:${combo}`,\n\t\t\t\t`two surfaces registered the shortcut \"${combo}\" at the same time — give each its own combo or scope one out.`\n\t\t\t)\n\t\t}\n\n\t\tconst onKey = (event: KeyboardEvent) => {\n\t\t\tif (event.repeat) return\n\t\t\t// `target` can be `window` itself; only elements can host a field.\n\t\t\tconst target = event.target\n\t\t\tif (\n\t\t\t\ttarget instanceof Element &&\n\t\t\t\ttarget.closest('input, textarea, select, [contenteditable]')\n\t\t\t) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (event.key.toLowerCase() !== spec.key) return\n\t\t\tif (spec.mod !== (event.metaKey || event.ctrlKey)) return\n\t\t\tif (spec.shift !== event.shiftKey) return\n\t\t\tif (spec.alt !== event.altKey) return\n\t\t\tevent.preventDefault()\n\t\t\thandlerRef.current()\n\t\t}\n\n\t\twindow.addEventListener('keydown', onKey)\n\t\treturn () => {\n\t\t\twindow.removeEventListener('keydown', onKey)\n\t\t\tconst count = (active.get(combo) ?? 1) - 1\n\t\t\tif (count <= 0) active.delete(combo)\n\t\t\telse active.set(combo, count)\n\t\t}\n\t}, [combo, disabled])\n}\n","import {\n\ttype ClipboardEvent,\n\ttype DragEvent,\n\ttype ReactNode,\n\tuseCallback,\n\tuseRef,\n\tuseState,\n} from 'react'\n\nimport { cn } from './cn'\nimport { Kbd } from './Kbd'\nimport { useCoarsePointer } from './useCoarsePointer'\nimport { formatShortcut, useShortcut } from './useShortcut'\n\nexport type DropzoneProps = {\n\taccept: string\n\tmultiple?: boolean\n\tdisabled?: boolean\n\t/**\n\t * Mobile camera shortcut: `'environment'` (rear) or `'user'` (front) makes\n\t * the file picker offer the camera directly on touch devices. Desktop\n\t * browsers ignore it.\n\t */\n\tcapture?: 'user' | 'environment'\n\t/** @defaultValue 'md' */\n\tsize?: 'sm' | 'md'\n\t/**\n\t * Global keyboard shortcut that opens this zone's picker, e.g. `'mod+u'`\n\t * (⌘U / Ctrl+U). A small key hint renders under the prompt on fine\n\t * pointers. With several zones on screen, give each its own combo.\n\t */\n\tshortcut?: string\n\tonFiles: (files: File[]) => void\n\tchildren: ReactNode\n\tclassName?: string\n}\n\n/**\n * The one drag-and-drop surface both uploaders share: drag state, click and\n * keyboard to browse, paste while focused (screenshots land as files), and a\n * hidden input. Presentation comes from `children`.\n */\nexport const Dropzone = ({\n\taccept,\n\tmultiple = false,\n\tdisabled = false,\n\tcapture,\n\tsize = 'md',\n\tshortcut,\n\tonFiles,\n\tchildren,\n\tclassName,\n}: DropzoneProps) => {\n\tconst inputRef = useRef<HTMLInputElement>(null)\n\tconst [dragging, setDragging] = useState(false)\n\t// Depth counter, not a boolean: entering a child fires `dragleave` on this\n\t// wrapper. See AGENTS.md §6.\n\tconst depth = useRef(0)\n\tconst coarse = useCoarsePointer()\n\tuseShortcut(shortcut, () => inputRef.current?.click(), disabled)\n\n\tconst emit = useCallback(\n\t\t(list: FileList | null) => {\n\t\t\tif (disabled || !list || list.length === 0) return\n\t\t\tonFiles(Array.from(list))\n\t\t},\n\t\t[disabled, onFiles]\n\t)\n\n\tconst onDrop = useCallback(\n\t\t(event: DragEvent) => {\n\t\t\tevent.preventDefault()\n\t\t\tdepth.current = 0\n\t\t\tsetDragging(false)\n\t\t\temit(event.dataTransfer.files)\n\t\t},\n\t\t[emit]\n\t)\n\n\tconst onPaste = useCallback(\n\t\t(event: ClipboardEvent) => {\n\t\t\t// A pasted screenshot arrives as a file; pasted text has none and\n\t\t\t// falls through untouched. Validation rejects what the scope won't.\n\t\t\tif (event.clipboardData.files.length === 0) return\n\t\t\tevent.preventDefault()\n\t\t\temit(event.clipboardData.files)\n\t\t},\n\t\t[emit]\n\t)\n\n\treturn (\n\t\t<div\n\t\t\trole='button'\n\t\t\ttabIndex={disabled ? -1 : 0}\n\t\t\taria-disabled={disabled}\n\t\t\tdata-dragging={dragging || undefined}\n\t\t\tonClick={() => !disabled && inputRef.current?.click()}\n\t\t\tonKeyDown={event => {\n\t\t\t\tif (disabled) return\n\t\t\t\tif (event.key === 'Enter' || event.key === ' ') {\n\t\t\t\t\tevent.preventDefault()\n\t\t\t\t\tinputRef.current?.click()\n\t\t\t\t}\n\t\t\t}}\n\t\t\tonDragEnter={() => {\n\t\t\t\tdepth.current += 1\n\t\t\t\tif (!disabled) setDragging(true)\n\t\t\t}}\n\t\t\tonDragOver={event => event.preventDefault()}\n\t\t\tonDragLeave={() => {\n\t\t\t\tdepth.current = Math.max(0, depth.current - 1)\n\t\t\t\tif (depth.current === 0) setDragging(false)\n\t\t\t}}\n\t\t\tonDrop={onDrop}\n\t\t\tonPaste={onPaste}\n\t\t\tclassName={cn(\n\t\t\t\t// `group/dz` + `data-dragging` let the children (the icon, the\n\t\t\t\t// prompt) react to hover and drag without owning any state.\n\t\t\t\t// `touch-manipulation` kills the 300ms tap delay; the active scale\n\t\t\t\t// is the press feedback a touch screen needs in place of hover.\n\t\t\t\t'group/dz rounded-ui-lg focus-visible:ring-ui-ring block w-full cursor-pointer touch-manipulation border-2 border-dashed text-center transition-all duration-200 focus-visible:ring-2 focus-visible:outline-none',\n\t\t\t\tsize === 'sm' ? 'p-3' : 'p-5',\n\t\t\t\tdragging\n\t\t\t\t\t? 'border-ui-primary bg-ui-primary-soft shadow-ui-primary/15 scale-[1.02] shadow-lg'\n\t\t\t\t\t: 'border-ui-border-strong hover:border-ui-primary/60 hover:bg-ui-primary-soft/40 hover:shadow-ui-primary/10 bg-ui-surface-subtle/50 hover:shadow-md',\n\t\t\t\t!disabled && 'active:scale-[0.98]',\n\t\t\t\tdisabled && 'cursor-not-allowed opacity-50',\n\t\t\t\tclassName\n\t\t\t)}\n\t\t>\n\t\t\t<input\n\t\t\t\tref={inputRef}\n\t\t\t\ttype='file'\n\t\t\t\taccept={accept}\n\t\t\t\tmultiple={multiple}\n\t\t\t\tdisabled={disabled}\n\t\t\t\t{...(capture ? { capture } : {})}\n\t\t\t\tclassName='hidden'\n\t\t\t\t// The wrapper's own `input.click()` bubbles back here and would\n\t\t\t\t// re-enter it. Load-bearing — see AGENTS.md §6.\n\t\t\t\tonClick={event => event.stopPropagation()}\n\t\t\t\tonChange={event => {\n\t\t\t\t\temit(event.target.files)\n\t\t\t\t\t// Same file picked twice must fire change again.\n\t\t\t\t\tevent.target.value = ''\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t{children}\n\t\t\t{shortcut && !coarse && (\n\t\t\t\t<span className='mt-2 block'>\n\t\t\t\t\t<Kbd>{formatShortcut(shortcut)}</Kbd>\n\t\t\t\t</span>\n\t\t\t)}\n\t\t</div>\n\t)\n}\n","import type { FileCategory, FileCategoryConfig, FileExtension } from './types'\n\nexport const KB = 1024\nexport const MB = 1024 * KB\nexport const GB = 1024 * MB\n\n/**\n * Leading bytes that identify a format regardless of its extension. The check\n * that uses them is the only defence against an executable renamed to `.pdf`,\n * since both the extension and the browser-reported MIME come from the client.\n */\nexport const MAGIC_NUMBERS: Partial<Record<FileExtension, number[]>> = {\n\tpng: [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a],\n\tjpg: [0xff, 0xd8, 0xff],\n\tjpeg: [0xff, 0xd8, 0xff],\n\tgif: [0x47, 0x49, 0x46, 0x38],\n\twebp: [0x52, 0x49, 0x46, 0x46], // RIFF; bytes 8-11 spell WEBP\n\tico: [0x00, 0x00, 0x01, 0x00],\n\n\tpdf: [0x25, 0x50, 0x44, 0x46], // %PDF\n\n\t// OOXML files are ZIP containers, so docx/xlsx share the PK signature.\n\tdocx: [0x50, 0x4b, 0x03, 0x04],\n\txlsx: [0x50, 0x4b, 0x03, 0x04],\n\tdoc: [0xd0, 0xcf, 0x11, 0xe0],\n\txls: [0xd0, 0xcf, 0x11, 0xe0],\n\n\t// DER/ASN.1 sequence header.\n\tcer: [0x30, 0x82],\n\tcrt: [0x30, 0x82],\n\tkey: [0x30, 0x82],\n\tpem: [0x2d, 0x2d, 0x2d, 0x2d, 0x2d], // -----\n\n\twebm: [0x1a, 0x45, 0xdf, 0xa3],\n\tavi: [0x52, 0x49, 0x46, 0x46],\n\tmp3: [0x49, 0x44, 0x33], // ID3\n\twav: [0x52, 0x49, 0x46, 0x46],\n\togg: [0x4f, 0x67, 0x67, 0x53],\n\taac: [0xff, 0xf1],\n}\n\nexport const MIME_TYPES: Record<FileExtension, string> = {\n\tpng: 'image/png',\n\tjpg: 'image/jpeg',\n\tjpeg: 'image/jpeg',\n\tsvg: 'image/svg+xml',\n\twebp: 'image/webp',\n\tgif: 'image/gif',\n\tico: 'image/x-icon',\n\theic: 'image/heic',\n\n\tcer: 'application/x-x509-ca-cert',\n\tcrt: 'application/x-x509-ca-cert',\n\tpem: 'application/x-pem-file',\n\tkey: 'application/x-pem-file',\n\n\tpdf: 'application/pdf',\n\tdoc: 'application/msword',\n\tdocx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n\txls: 'application/vnd.ms-excel',\n\txlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n\tcsv: 'text/csv',\n\ttxt: 'text/plain',\n\n\txml: 'application/xml',\n\tjson: 'application/json',\n\n\tmp4: 'video/mp4',\n\tmov: 'video/quicktime',\n\tavi: 'video/x-msvideo',\n\twebm: 'video/webm',\n\n\tmp3: 'audio/mpeg',\n\twav: 'audio/wav',\n\togg: 'audio/ogg',\n\taac: 'audio/aac',\n}\n\n/**\n * Defaults per category. A scope always narrows these; it can never widen the\n * extension list, which is what keeps `any` from leaking into a strict scope.\n */\nexport const FILE_CATEGORY_CONFIG: Record<FileCategory, FileCategoryConfig> = {\n\timage: {\n\t\textensions: ['png', 'jpg', 'jpeg', 'svg', 'webp', 'gif'],\n\t\tmaxBytes: 5 * MB,\n\t\tvalidateMagicNumbers: true,\n\t\tlabel: 'image',\n\t\taccept: 'image/*',\n\t},\n\tcertificate: {\n\t\textensions: ['cer', 'crt', 'pem'],\n\t\tmaxBytes: 50 * KB,\n\t\tvalidateMagicNumbers: true,\n\t\tlabel: 'certificate',\n\t\taccept: '.cer,.crt,.pem',\n\t},\n\tkey: {\n\t\textensions: ['key'],\n\t\tmaxBytes: 50 * KB,\n\t\tvalidateMagicNumbers: true,\n\t\tlabel: 'private key',\n\t\taccept: '.key',\n\t},\n\tpdf: {\n\t\textensions: ['pdf'],\n\t\tmaxBytes: 20 * MB,\n\t\tvalidateMagicNumbers: true,\n\t\tlabel: 'PDF',\n\t\taccept: '.pdf',\n\t},\n\tdocument: {\n\t\textensions: ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'csv', 'txt'],\n\t\tmaxBytes: 20 * MB,\n\t\tvalidateMagicNumbers: false,\n\t\tlabel: 'document',\n\t\taccept: '.pdf,.doc,.docx,.xls,.xlsx,.csv,.txt',\n\t},\n\tdata: {\n\t\textensions: ['xml', 'json'],\n\t\tmaxBytes: 5 * MB,\n\t\tvalidateMagicNumbers: false,\n\t\tlabel: 'data file',\n\t\taccept: '.xml,.json',\n\t},\n\tvideo: {\n\t\textensions: ['mp4', 'mov', 'avi', 'webm'],\n\t\tmaxBytes: 100 * MB,\n\t\tvalidateMagicNumbers: false,\n\t\tlabel: 'video',\n\t\taccept: 'video/*',\n\t},\n\taudio: {\n\t\textensions: ['mp3', 'wav', 'ogg', 'aac'],\n\t\tmaxBytes: 20 * MB,\n\t\tvalidateMagicNumbers: false,\n\t\tlabel: 'audio',\n\t\taccept: 'audio/*',\n\t},\n\tany: {\n\t\textensions: [],\n\t\tmaxBytes: 20 * MB,\n\t\tvalidateMagicNumbers: false,\n\t\tlabel: 'file',\n\t\taccept: '*/*',\n\t},\n}\n","import { MIME_TYPES } from './constants'\nimport type { FileExtension, FileLike } from './types'\n\n/** Lower-case extension without the dot, or `''` when the name has none. */\nexport const getFileExtension = (fileName: string): string => {\n\tconst dot = fileName.lastIndexOf('.')\n\tif (dot < 1 || dot === fileName.length - 1) return ''\n\treturn fileName.slice(dot + 1).toLowerCase()\n}\n\nexport const getMimeType = (fileName: string): string => {\n\tconst ext = getFileExtension(fileName) as FileExtension\n\treturn MIME_TYPES[ext] ?? 'application/octet-stream'\n}\n\nexport const isKnownExtension = (value: string): value is FileExtension =>\n\tvalue in MIME_TYPES\n\nexport const formatFileSize = (bytes: number): string => {\n\tif (bytes < 1024) return `${bytes} B`\n\tconst units = ['KB', 'MB', 'GB', 'TB']\n\tlet size = bytes / 1024\n\tlet unit = 0\n\twhile (size >= 1024 && unit < units.length - 1) {\n\t\tsize /= 1024\n\t\tunit++\n\t}\n\treturn `${size.toFixed(size >= 10 ? 0 : 1)} ${units[unit]}`\n}\n\n/** Longest stem kept. Object stores cap the whole key and the prefix spends part of it. */\nconst MAX_STEM_LENGTH = 80\n\n/** What an all-punctuation name degrades to, so a key never ends in a bare dot. */\nconst FALLBACK_STEM = 'file'\n\nconst slugSegment = (value: string): string =>\n\tvalue\n\t\t.normalize('NFD')\n\t\t.replace(/[\\u0300-\\u036f]/g, '')\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9]+/g, '-')\n\t\t.replace(/^-+|-+$/g, '')\n\n/**\n * Turns a user's file name into a safe key segment: ASCII, lower case, one\n * extension, no path syntax.\n *\n * Call it INSIDE your scope's `path()`, not around it:\n *\n * ```ts\n * path: (id, file) => `Docs/${id}/${sanitizeFileName(file.name)}`\n * ```\n *\n * `resolveKey` deliberately does not apply it for you. It would rewrite the key\n * your `path()` returned, and a client computing the same key to decide replace\n * mode would then disagree with the server. Inside `path()` both sides run the\n * one function and cannot drift.\n *\n * This exists because a macOS screenshot took an API down. `Screenshot\n * 2026-08-31 at 4.18.54 p.m..png` ends in `p.m.` + `.png`, so the raw name\n * carries `..`; the traversal guard rejected the key and the consumer dropped\n * the rejection, killing the process.\n *\n * Only the KEY is slugged — keep the original in `StoredFile.fileName`, which\n * is what a UI should render.\n */\nexport const sanitizeFileName = (fileName: string): string => {\n\t// A name arriving as a path is already an attempt, deliberate or not.\n\tconst base = fileName.split(/[/\\\\]/).pop() ?? ''\n\n\tconst dot = base.lastIndexOf('.')\n\t// A leading dot is a dotfile, not an extension: `.env` has no stem.\n\tconst hasExtension = dot > 0\n\tconst stem = slugSegment(hasExtension ? base.slice(0, dot) : base).slice(\n\t\t0,\n\t\tMAX_STEM_LENGTH\n\t)\n\tconst extension = hasExtension ? slugSegment(base.slice(dot + 1)) : ''\n\n\t// A trailing `-` can reappear when the length cut lands mid-separator.\n\tconst safeStem = stem.replace(/-+$/, '') || FALLBACK_STEM\n\n\treturn extension ? `${safeStem}.${extension}` : safeStem\n}\n\n/** Value for an `<input accept=\"…\">` built from an extension list. */\nexport const toAcceptAttribute = (extensions: FileExtension[]): string =>\n\textensions.length === 0\n\t\t? '*/*'\n\t\t: extensions.map(extension => `.${extension}`).join(',')\n\n/**\n * Adapts a multer memory-storage file to `FileLike` so server code validates\n * with the very same function the browser ran.\n */\nexport const fromMulterFile = (file: {\n\toriginalname: string\n\tsize: number\n\tmimetype: string\n\tbuffer: Uint8Array\n}): FileLike => ({\n\tname: file.originalname,\n\tsize: file.size,\n\ttype: file.mimetype,\n\tarrayBuffer: async () =>\n\t\tfile.buffer.buffer.slice(\n\t\t\tfile.buffer.byteOffset,\n\t\t\tfile.buffer.byteOffset + file.buffer.byteLength\n\t\t) as ArrayBuffer,\n})\n","import { getFileExtension } from '../file'\nimport { cn } from './cn'\n\nexport type FileTypeBadgeProps = {\n\t/** Omit for an empty position — the same square, dashed. */\n\tfileName?: string\n\t/** Local thumbnail for images; falls back to the extension chip. */\n\tpreview?: string\n\t/** @defaultValue 'md' */\n\tsize?: 'sm' | 'md'\n}\n\n/**\n * The 40x40 leading square of a file row: the image thumbnail when there is\n * one, the extension in a grey chip when there is a file, and a dashed\n * placeholder when the position is empty. Same size in all three, so a row does\n * not jump the moment a file lands in it.\n */\nexport const FileTypeBadge = ({\n\tfileName,\n\tpreview,\n\tsize = 'md',\n}: FileTypeBadgeProps) => {\n\tconst box = size === 'sm' ? 'h-8 w-8' : 'h-10 w-10'\n\tif (!fileName) {\n\t\treturn (\n\t\t\t<span\n\t\t\t\taria-hidden='true'\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'border-ui-border rounded-ui shrink-0 border border-dashed',\n\t\t\t\t\tbox\n\t\t\t\t)}\n\t\t\t/>\n\t\t)\n\t}\n\treturn preview ? (\n\t\t<img\n\t\t\tsrc={preview}\n\t\t\talt=''\n\t\t\tclassName={cn('rounded-ui shrink-0 object-cover', box)}\n\t\t/>\n\t) : (\n\t\t<span\n\t\t\tclassName={cn(\n\t\t\t\t'bg-ui-surface-muted text-ui-muted rounded-ui flex shrink-0 items-center justify-center font-medium uppercase',\n\t\t\t\tsize === 'sm' ? 'text-[10px]' : 'text-xs',\n\t\t\t\tbox\n\t\t\t)}\n\t\t>\n\t\t\t{getFileExtension(fileName)}\n\t\t</span>\n\t)\n}\n","import { cn } from './cn'\n\nexport type ProgressBarProps = {\n\t/** 0–100. */\n\tpercent: number\n\tclassName?: string\n}\n\n/**\n * The thin in-flight bar under a file's name — a grey track with a blue fill.\n * Shared by every upload row so progress reads the same wherever it appears.\n */\nexport const ProgressBar = ({ percent, className }: ProgressBarProps) => (\n\t<div\n\t\tclassName={cn(\n\t\t\t'bg-ui-surface-muted mt-1 h-1 w-full overflow-hidden rounded',\n\t\t\tclassName\n\t\t)}\n\t>\n\t\t<div\n\t\t\tclassName='bg-ui-primary h-full transition-all'\n\t\t\tstyle={{ width: `${percent}%` }}\n\t\t/>\n\t</div>\n)\n","import { formatFileSize } from '../file'\nimport type { UploaderLabels } from '../labels'\nimport type { UploaderFile } from '../react'\nimport { useUploaderLabels } from '../react/UploaderProvider'\nimport { cn } from './cn'\nimport { FileTypeBadge } from './FileTypeBadge'\nimport { ProgressBar } from './ProgressBar'\n\nexport type FileItemProps = {\n\tfile: UploaderFile\n\tonRemove: () => void\n\tonAbort: () => void\n\t/** Present on successes when a viewer is available. */\n\tonView?: () => void\n\t/** @defaultValue 'md' */\n\tsize?: 'sm' | 'md'\n\tlabels?: Partial<UploaderLabels>\n}\n\n/**\n * One row of upload state: preview/extension badge, name, size, a progress\n * bar while in flight, the error when it failed. Shared by both uploaders so\n * a file always looks the same wherever it is being uploaded.\n */\nexport const FileItem = ({\n\tfile,\n\tonRemove,\n\tonAbort,\n\tonView,\n\tsize = 'md',\n\tlabels,\n}: FileItemProps) => {\n\tconst copy = useUploaderLabels(labels)\n\tconst uploading = file.status === 'uploading'\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'rounded-ui animate-ui-fade-in flex items-center gap-3 border text-sm transition-colors',\n\t\t\t\tsize === 'sm' ? 'p-1.5' : 'p-2',\n\t\t\t\tfile.status === 'error'\n\t\t\t\t\t? 'border-ui-danger-soft-fg/20 bg-ui-danger-soft'\n\t\t\t\t\t: 'border-ui-border bg-ui-surface'\n\t\t\t)}\n\t\t>\n\t\t\t<FileTypeBadge\n\t\t\t\tfileName={file.file.name}\n\t\t\t\tpreview={file.preview}\n\t\t\t\tsize={size}\n\t\t\t/>\n\n\t\t\t<div className='min-w-0 flex-1'>\n\t\t\t\t<p className='text-ui-fg truncate font-medium'>{file.file.name}</p>\n\t\t\t\t{file.status === 'error' ? (\n\t\t\t\t\t<p className='text-ui-danger text-xs'>{file.error}</p>\n\t\t\t\t) : (\n\t\t\t\t\t<p className='text-ui-muted text-xs'>\n\t\t\t\t\t\t{formatFileSize(file.file.size)}\n\t\t\t\t\t\t{file.status === 'success' && ` · ${copy.ready}`}\n\t\t\t\t\t\t{file.status === 'idle' && ` · ${copy.staged}`}\n\t\t\t\t\t</p>\n\t\t\t\t)}\n\t\t\t\t{uploading && <ProgressBar percent={file.progress} />}\n\t\t\t</div>\n\n\t\t\t{onView && (\n\t\t\t\t<button\n\t\t\t\t\ttype='button'\n\t\t\t\t\tonClick={onView}\n\t\t\t\t\tclassName='text-ui-primary hover:bg-ui-primary-soft focus-visible:ring-ui-ring rounded-ui shrink-0 cursor-pointer px-2 py-1 text-xs transition-colors focus-visible:ring-2 focus-visible:outline-none'\n\t\t\t\t>\n\t\t\t\t\t{copy.view}\n\t\t\t\t</button>\n\t\t\t)}\n\t\t\t<button\n\t\t\t\ttype='button'\n\t\t\t\tonClick={uploading ? onAbort : onRemove}\n\t\t\t\tclassName='text-ui-muted hover:bg-ui-surface-muted hover:text-ui-fg focus-visible:ring-ui-ring rounded-ui shrink-0 cursor-pointer px-2 py-1 text-xs transition-colors focus-visible:ring-2 focus-visible:outline-none'\n\t\t\t>\n\t\t\t\t{uploading ? copy.cancel : copy.remove}\n\t\t\t</button>\n\t\t</div>\n\t)\n}\n","/**\n * The built-in glyphs, kept to the few the package's own chrome needs — the\n * dropzone default and the viewer's header actions, which have no text on a\n * touch screen. Consumers replace the dropzone one per uploader via the `icon`\n * prop (any ReactNode); none of these is exported, so the package never grows\n * into an icon library.\n */\nexport const UploadCloudIcon = ({ className }: { className?: string }) => (\n\t<svg\n\t\tviewBox='0 0 24 24'\n\t\tfill='none'\n\t\tstroke='currentColor'\n\t\tstrokeWidth='1.75'\n\t\tstrokeLinecap='round'\n\t\tstrokeLinejoin='round'\n\t\tclassName={className}\n\t\taria-hidden\n\t>\n\t\t<path d='M4 14.9A7 7 0 1 1 15.7 8h1.8a4.5 4.5 0 0 1 2.5 8.2' />\n\t\t<path d='M12 12v9' />\n\t\t<path d='m8 16 4-4 4 4' />\n\t</svg>\n)\n\n/** Viewer header: save the file being previewed. */\nexport const DownloadIcon = ({ className }: { className?: string }) => (\n\t<svg\n\t\tviewBox='0 0 24 24'\n\t\tfill='none'\n\t\tstroke='currentColor'\n\t\tstrokeWidth='1.75'\n\t\tstrokeLinecap='round'\n\t\tstrokeLinejoin='round'\n\t\tclassName={className}\n\t\taria-hidden\n\t>\n\t\t<path d='M12 3v12' />\n\t\t<path d='m7 11 5 5 5-5' />\n\t\t<path d='M4 20h16' />\n\t</svg>\n)\n\n/** Viewer header: open the file in its own tab. */\nexport const ExternalLinkIcon = ({ className }: { className?: string }) => (\n\t<svg\n\t\tviewBox='0 0 24 24'\n\t\tfill='none'\n\t\tstroke='currentColor'\n\t\tstrokeWidth='1.75'\n\t\tstrokeLinecap='round'\n\t\tstrokeLinejoin='round'\n\t\tclassName={className}\n\t\taria-hidden\n\t>\n\t\t<path d='M14 4h6v6' />\n\t\t<path d='M20 4 10 14' />\n\t\t<path d='M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5' />\n\t</svg>\n)\n\n/** Viewer: the preview could not be rendered. */\nexport const FileWarningIcon = ({ className }: { className?: string }) => (\n\t<svg\n\t\tviewBox='0 0 24 24'\n\t\tfill='none'\n\t\tstroke='currentColor'\n\t\tstrokeWidth='1.5'\n\t\tstrokeLinecap='round'\n\t\tstrokeLinejoin='round'\n\t\tclassName={className}\n\t\taria-hidden\n\t>\n\t\t<path d='M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z' />\n\t\t<path d='M14 3v5h5' />\n\t\t<path d='M12 11v4' />\n\t\t<path d='M12 18h.01' />\n\t</svg>\n)\n","import { type ReactNode, useCallback, useEffect, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { getMimeType } from '../file'\nimport type { UploaderLabels } from '../labels'\nimport { useUploaderLabels } from '../react/UploaderProvider'\nimport { cn } from './cn'\nimport { DownloadIcon, ExternalLinkIcon, FileWarningIcon } from './icons'\nimport { Kbd } from './Kbd'\nimport { useOverlayLayer } from './overlayStack'\nimport { lockBodyScroll, unlockBodyScroll } from './scrollLock'\nimport { useCoarsePointer } from './useCoarsePointer'\nimport { useFocusTrap } from './useFocusTrap'\nimport { useOverlayTransition } from './useOverlayTransition'\n\n/**\n * The viewer's empty states — failure and \"no preview\" — speak the overlay's\n * own language: no card, white on the black scrim, the same translucent\n * controls as the header. Theme tokens are deliberately absent: this component\n * ships inside many apps, and a surface-coloured panel would read as a stray\n * card from whichever one is hosting it.\n */\nconst EMPTY_STATE_CLASS = 'mx-4 flex max-w-sm flex-col items-center text-center'\nconst EMPTY_TITLE_CLASS = 'text-sm font-medium text-white'\nconst EMPTY_HINT_CLASS = 'mt-1.5 text-xs leading-relaxed text-white/60'\n/** Primary sits one step brighter than the header actions, never coloured. */\nconst EMPTY_PRIMARY_CLASS =\n\t'focus-visible:ring-ui-ring rounded-ui cursor-pointer bg-white/20 px-4 py-2 text-sm text-white transition-colors hover:bg-white/30 focus-visible:ring-2 focus-visible:outline-none'\nconst EMPTY_SECONDARY_CLASS =\n\t'focus-visible:ring-ui-ring rounded-ui cursor-pointer border border-white/20 px-4 py-2 text-sm text-white/80 transition-colors hover:bg-white/10 hover:text-white focus-visible:ring-2 focus-visible:outline-none'\n\n/** Shared chrome of the header actions, so the three stay one control strip. */\nconst ACTION_CLASS =\n\t'focus-visible:ring-ui-ring rounded-ui inline-flex shrink-0 cursor-pointer items-center gap-1.5 bg-white/10 px-3 py-1.5 text-xs whitespace-nowrap text-white transition-colors hover:bg-white/20 focus-visible:ring-2 focus-visible:outline-none'\n\n/** What the viewer needs to render a file — a StoredFile satisfies it. */\nexport type ViewableFile = {\n\turl: string\n\tfileName?: string\n\tmimeType?: string\n}\n\nexport type FileViewerProps = {\n\t/** File to show; `null` keeps the viewer closed. */\n\tfile: ViewableFile | null\n\tonClose: () => void\n\t/**\n\t * The collection to browse. With more than one entry the viewer gains side\n\t * arrows and ←/→ keyboard navigation, starting at `file`'s position.\n\t */\n\tfiles?: ViewableFile[]\n\t/**\n\t * Resolve a fresh URL right before rendering — the hook for private scopes,\n\t * where the persisted signed URL may have expired and the app re-signs via\n\t * its /storage signed-url endpoint.\n\t */\n\tresolveUrl?: (file: ViewableFile) => Promise<string>\n\t/**\n\t * Replaces the built-in \"could not load\" panel. Receives the file that\n\t * failed and a `retry` that re-resolves and re-renders it, so a custom\n\t * panel keeps the recovery the default one offers.\n\t */\n\trenderError?: (context: {\n\t\tfile: ViewableFile\n\t\tretry: () => void\n\t}) => ReactNode\n\tlabels?: Partial<UploaderLabels>\n}\n\ntype Kind = 'image' | 'pdf' | 'other'\n\nconst kindOf = (file: ViewableFile): Kind => {\n\tconst mime = file.mimeType || getMimeType(file.fileName ?? file.url)\n\tif (mime.startsWith('image/')) return 'image'\n\tif (mime === 'application/pdf') return 'pdf'\n\treturn 'other'\n}\n\n/**\n * iPadOS 13+ reports itself as a Mac, so the platform string alone misses it;\n * a Mac with a touchscreen is the tell.\n */\nconst isIosWebkit = (): boolean => {\n\tconst ua = navigator.userAgent\n\treturn (\n\t\t/iPad|iPhone|iPod/.test(ua) ||\n\t\t(ua.includes('Macintosh') && navigator.maxTouchPoints > 1)\n\t)\n}\n\n/**\n * Whether an `<iframe>` will actually RENDER a PDF here.\n *\n * This used to be a `max-width: 640px` media query standing in for \"iOS\n * Safari\". It punished every narrow viewport — a half-width desktop window, a\n * phone on Chrome — with the \"no preview\" card, while iPadOS, which is wider\n * than the breakpoint AND genuinely broken, sailed past it into a blank frame.\n *\n * `pdfViewerEnabled` is the browser answering the question directly (it is\n * false on Android Chrome, which downloads instead of embedding). WebKit on iOS\n * answers yes and then paints a frozen first page, so it stays excluded by\n * name.\n */\nconst browserEmbedsPdf = (): boolean => {\n\tif (typeof navigator === 'undefined') return false\n\tif (navigator.pdfViewerEnabled === false) return false\n\treturn !isIosWebkit()\n}\n\nconst Chevron = ({ direction }: { direction: 'left' | 'right' }) => (\n\t<svg\n\t\tviewBox='0 0 24 24'\n\t\tfill='none'\n\t\tstroke='currentColor'\n\t\tstrokeWidth='2.5'\n\t\tstrokeLinecap='round'\n\t\tstrokeLinejoin='round'\n\t\tclassName='h-5 w-5'\n\t\taria-hidden\n\t>\n\t\t{direction === 'left' ? (\n\t\t\t<path d='m15 18-6-6 6-6' />\n\t\t) : (\n\t\t\t<path d='m9 18 6-6-6-6' />\n\t\t)}\n\t</svg>\n)\n\n/**\n * Full-screen file preview: images zoomed to fit, PDFs embedded, anything\n * else offered as a download — no more blind new-tab jumps. Pass `files` and\n * it becomes a gallery: side arrows, ←/→ on the keyboard, a position counter.\n * Used internally by `Uploader` and `SlottedUploader`, and exported standalone\n * so any screen can preview the `StoredFile`s it persisted.\n *\n * Portals to `<body>` so an ancestor's stacking context can never trap it,\n * and traps focus while open.\n */\nexport const FileViewer = ({\n\tfile,\n\tonClose,\n\tfiles,\n\tresolveUrl,\n\trenderError,\n\tlabels,\n}: FileViewerProps) => {\n\tconst copy = useUploaderLabels(labels)\n\tconst coarse = useCoarsePointer()\n\tconst [url, setUrl] = useState<string | null>(null)\n\tconst [failed, setFailed] = useState(false)\n\t// Bumping it re-runs the resolution — the retry button after a failure.\n\tconst [attempt, setAttempt] = useState(0)\n\tconst retry = useCallback(() => setAttempt(previous => previous + 1), [])\n\tconst panelRef = useRef<HTMLDivElement>(null)\n\tconst open = file !== null\n\tconst { mounted, entered } = useOverlayTransition(open)\n\tconst layer = useOverlayLayer(open)\n\tuseFocusTrap(open, panelRef)\n\n\t// Gallery cursor. Synced to `file`'s position whenever the viewer opens.\n\tconst list = files && files.length > 0 ? files : null\n\tconst [cursor, setCursor] = useState(0)\n\tuseEffect(() => {\n\t\tif (!file || !list) return\n\t\tconst index = list.findIndex(entry => entry.url === file.url)\n\t\tsetCursor(index >= 0 ? index : 0)\n\t\t// Only the opening file may reposition the cursor, not a list rebuild.\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, [file])\n\n\tconst current = open ? (list ? (list[cursor] ?? file) : file) : null\n\n\t// The exit animation still needs something to draw after `file` nulls out.\n\tconst lastViewRef = useRef<ViewableFile | null>(null)\n\tif (current) lastViewRef.current = current\n\n\tconst navigate = useCallback(\n\t\t(delta: number) => {\n\t\t\tif (!list) return\n\t\t\tsetCursor(previous =>\n\t\t\t\tMath.min(list.length - 1, Math.max(0, previous + delta))\n\t\t\t)\n\t\t},\n\t\t[list]\n\t)\n\n\t// The viewer resolves, so the viewer owns what the resolution minted: a\n\t// `createBlobUrlResolver` hands back a `blob:` whose BYTES stay alive until\n\t// something revokes it, and browsing a gallery mints one per file.\n\tconst objectUrlRef = useRef<string | null>(null)\n\tconst releaseObjectUrl = useCallback(() => {\n\t\tif (objectUrlRef.current) URL.revokeObjectURL(objectUrlRef.current)\n\t\tobjectUrlRef.current = null\n\t}, [])\n\n\t// In a ref, not the deps: callers pass an inline arrow and re-signing is a\n\t// round trip. Only the viewed file (or an explicit retry) may re-run it.\n\tconst resolveRef = useRef(resolveUrl)\n\tresolveRef.current = resolveUrl\n\tconst currentUrl = current?.url\n\n\tuseEffect(() => {\n\t\t// Before the early return: closing the viewer nulls `current`, and that\n\t\t// is exactly when the last blob has to go.\n\t\treleaseObjectUrl()\n\t\tif (!current) {\n\t\t\tsetUrl(null)\n\t\t\tsetFailed(false)\n\t\t\treturn\n\t\t}\n\t\tlet alive = true\n\t\tsetUrl(null)\n\t\tsetFailed(false)\n\t\tvoid (async () => {\n\t\t\ttry {\n\t\t\t\tconst resolve = resolveRef.current\n\t\t\t\tconst resolved = resolve ? await resolve(current) : current.url\n\t\t\t\tconst minted = resolved.startsWith('blob:')\n\t\t\t\tif (!alive) {\n\t\t\t\t\t// Superseded mid-flight: nothing will ever render it, so it has\n\t\t\t\t\t// to go now or it is unreachable AND alive.\n\t\t\t\t\tif (minted) URL.revokeObjectURL(resolved)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t// A signed url belongs to the server; only a blob is ours to free.\n\t\t\t\tif (minted) objectUrlRef.current = resolved\n\t\t\t\tsetUrl(resolved)\n\t\t\t} catch {\n\t\t\t\t// An expired signature or a dropped connection must surface as a\n\t\t\t\t// retryable state, never as an eternal \"Cargando…\".\n\t\t\t\tif (alive) {\n\t\t\t\t\tsetUrl(null)\n\t\t\t\t\tsetFailed(true)\n\t\t\t\t}\n\t\t\t}\n\t\t})()\n\t\treturn () => {\n\t\t\talive = false\n\t\t}\n\t\t// `currentUrl` stands in for `current`: a rebuilt array with the same\n\t\t// entry must not re-sign.\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, [currentUrl, attempt])\n\n\t// The effect above frees on every change; this catches the last one.\n\tuseEffect(() => releaseObjectUrl, [releaseObjectUrl])\n\n\tconst closeRef = useRef(onClose)\n\tcloseRef.current = onClose\n\n\t// Clicking the anchors is what downloads/opens: replicating their behaviour\n\t// from a handler would mean re-deriving `download` and popup rules.\n\tconst downloadRef = useRef<HTMLAnchorElement>(null)\n\tconst openTabRef = useRef<HTMLAnchorElement>(null)\n\n\tuseEffect(() => {\n\t\tif (!open) return\n\t\tconst onKey = (event: KeyboardEvent) => {\n\t\t\t// A modifier means the key belongs to the browser (⌘D bookmarks,\n\t\t\t// ⌘O opens a file): claiming it would fire our action AND theirs.\n\t\t\tif (event.metaKey || event.ctrlKey || event.altKey) return\n\t\t\tif (event.key === 'Escape') {\n\t\t\t\t// Only the innermost overlay answers, then claims the key so a\n\t\t\t\t// host dialog underneath does not close on the same press.\n\t\t\t\tif (!layer.isTopmost()) return\n\t\t\t\tevent.stopPropagation()\n\t\t\t\tcloseRef.current()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (event.key === 'ArrowLeft') navigate(-1)\n\t\t\tif (event.key === 'ArrowRight') navigate(1)\n\t\t\t// Bare letters, like the arrows above: the viewer is modal and\n\t\t\t// traps focus, so nothing else can be listening.\n\t\t\tconst key = event.key.toLowerCase()\n\t\t\tif (key === 'd') downloadRef.current?.click()\n\t\t\tif (key === 'o') openTabRef.current?.click()\n\t\t}\n\t\t// Capture phase: it must run BEFORE any bubble-phase dialog handler.\n\t\twindow.addEventListener('keydown', onKey, true)\n\t\tlockBodyScroll()\n\t\treturn () => {\n\t\t\twindow.removeEventListener('keydown', onKey, true)\n\t\t\tunlockBodyScroll()\n\t\t}\n\t}, [open, navigate, layer])\n\n\t// Lazy initializer, not an effect: `navigator` cannot change under the\n\t// component, and starting at `true` painted one iframe frame on iOS before\n\t// correcting to the download card.\n\tconst [canEmbedPdf] = useState(browserEmbedsPdf)\n\n\tconst view = current ?? lastViewRef.current\n\tif (!mounted || !view) return null\n\tconst kind = kindOf(view)\n\t// Drives BOTH the branch and the stretch class: the iframe is the only\n\t// child that fills its container, and letting the two drift is what pinned\n\t// a failed PDF's message to the top edge.\n\tconst showsPdf = kind === 'pdf' && canEmbedPdf && !failed && !!url\n\tconst hasGallery = list !== null && list.length > 1\n\n\tconst arrow =\n\t\t'absolute top-1/2 z-10 flex h-11 w-11 -translate-y-1/2 cursor-pointer items-center justify-center rounded-full bg-white/10 text-white backdrop-blur-sm transition-all duration-200 hover:bg-white/25 focus-visible:ring-2 focus-visible:ring-ui-ring focus-visible:outline-none disabled:pointer-events-none disabled:opacity-25'\n\n\treturn createPortal(\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'fixed inset-0 z-1000 flex flex-col bg-black/85 transition-opacity duration-200 ease-out',\n\t\t\t\tentered ? 'opacity-100' : 'opacity-0',\n\t\t\t\t!open && 'pointer-events-none'\n\t\t\t)}\n\t\t\tonClick={onClose}\n\t\t\trole='dialog'\n\t\t\taria-modal='true'\n\t\t\taria-label={view.fileName ?? copy.filePreview}\n\t\t>\n\t\t\t<div\n\t\t\t\tclassName='flex items-center justify-between gap-2 px-3 py-2.5 sm:gap-3 sm:px-4 sm:py-3'\n\t\t\t\tonClick={event => event.stopPropagation()}\n\t\t\t>\n\t\t\t\t<p className='min-w-0 flex-1 truncate text-xs font-medium text-white sm:text-sm'>\n\t\t\t\t\t{view.fileName ?? copy.filePreview}\n\t\t\t\t</p>\n\t\t\t\t{hasGallery && (\n\t\t\t\t\t<span className='shrink-0 rounded-full bg-white/10 px-2.5 py-1 text-[11px] font-medium text-white tabular-nums'>\n\t\t\t\t\t\t{cursor + 1} / {list.length}\n\t\t\t\t\t</span>\n\t\t\t\t)}\n\t\t\t\t{/* Three actions plus a title do not fit a phone, so a coarse\n\t\t\t\t pointer gets glyphs and the labels move to `aria-label`. */}\n\t\t\t\t{url && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\tref={downloadRef}\n\t\t\t\t\t\t\thref={url}\n\t\t\t\t\t\t\tdownload={view.fileName}\n\t\t\t\t\t\t\taria-label={copy.downloadShort}\n\t\t\t\t\t\t\ttitle={copy.downloadShort}\n\t\t\t\t\t\t\tclassName={ACTION_CLASS}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{coarse ? (\n\t\t\t\t\t\t\t\t<DownloadIcon className='h-4 w-4' />\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\tcopy.downloadShort\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\tref={openTabRef}\n\t\t\t\t\t\t\thref={url}\n\t\t\t\t\t\t\ttarget='_blank'\n\t\t\t\t\t\t\trel='noreferrer'\n\t\t\t\t\t\t\taria-label={copy.openInTab}\n\t\t\t\t\t\t\ttitle={copy.openInTab}\n\t\t\t\t\t\t\tclassName={ACTION_CLASS}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{coarse ? (\n\t\t\t\t\t\t\t\t<ExternalLinkIcon className='h-4 w-4' />\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\tcopy.openInTab\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t\t<button\n\t\t\t\t\ttype='button'\n\t\t\t\t\tonClick={onClose}\n\t\t\t\t\taria-label={copy.close}\n\t\t\t\t\ttitle={copy.close}\n\t\t\t\t\tclassName={ACTION_CLASS}\n\t\t\t\t>\n\t\t\t\t\t{coarse ? '✕' : <>✕ {copy.close}</>}\n\t\t\t\t</button>\n\t\t\t</div>\n\n\t\t\t<div\n\t\t\t\tref={panelRef}\n\t\t\t\ttabIndex={-1}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'relative flex min-h-0 flex-1 items-center justify-center p-3 outline-none sm:p-4',\n\t\t\t\t\tshowsPdf && 'items-stretch'\n\t\t\t\t)}\n\t\t\t\tonClick={event => event.stopPropagation()}\n\t\t\t>\n\t\t\t\t{hasGallery && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype='button'\n\t\t\t\t\t\t\tonClick={() => navigate(-1)}\n\t\t\t\t\t\t\tdisabled={cursor === 0}\n\t\t\t\t\t\t\taria-label={copy.previous}\n\t\t\t\t\t\t\tclassName={cn(arrow, 'left-2 sm:left-4')}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Chevron direction='left' />\n\t\t\t\t\t\t</button>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype='button'\n\t\t\t\t\t\t\tonClick={() => navigate(1)}\n\t\t\t\t\t\t\tdisabled={cursor === list.length - 1}\n\t\t\t\t\t\t\taria-label={copy.next}\n\t\t\t\t\t\t\tclassName={cn(arrow, 'right-2 sm:right-4')}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Chevron direction='right' />\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</>\n\t\t\t\t)}\n\n\t\t\t\t{failed ? (\n\t\t\t\t\t(renderError?.({ file: view, retry }) ?? (\n\t\t\t\t\t\t<div className={EMPTY_STATE_CLASS}>\n\t\t\t\t\t\t\t<span className='mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-white/5 text-white/70 ring-1 ring-white/10'>\n\t\t\t\t\t\t\t\t<FileWarningIcon className='h-8 w-8' />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t<p className={EMPTY_TITLE_CLASS}>{copy.viewerError}</p>\n\t\t\t\t\t\t\t<p className={EMPTY_HINT_CLASS}>{copy.viewerErrorHint}</p>\n\t\t\t\t\t\t\t{view.fileName && (\n\t\t\t\t\t\t\t\t<p className='mt-3 max-w-full truncate font-mono text-[11px] text-white/40'>\n\t\t\t\t\t\t\t\t\t{view.fileName}\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t<div className='mt-5 flex flex-wrap justify-center gap-2'>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype='button'\n\t\t\t\t\t\t\t\t\tonClick={retry}\n\t\t\t\t\t\t\t\t\tclassName={EMPTY_PRIMARY_CLASS}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{copy.viewerRetry}\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t{/* The bytes may still be reachable even when\n\t\t\t\t\t\t\t\t the preview is not — never a dead end. */}\n\t\t\t\t\t\t\t\t{url && (\n\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\thref={url}\n\t\t\t\t\t\t\t\t\t\tdownload={view.fileName}\n\t\t\t\t\t\t\t\t\t\tclassName={EMPTY_SECONDARY_CLASS}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{copy.downloadShort}\n\t\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))\n\t\t\t\t) : !url ? (\n\t\t\t\t\t<p className='text-sm text-white/70'>{copy.viewerLoading}</p>\n\t\t\t\t) : kind === 'image' ? (\n\t\t\t\t\t<img\n\t\t\t\t\t\tsrc={url}\n\t\t\t\t\t\talt={view.fileName ?? ''}\n\t\t\t\t\t\t// A resolved url only proves the address; the object\n\t\t\t\t\t\t// behind it can still 404, and an untracked failure\n\t\t\t\t\t\t// renders as an invisible image.\n\t\t\t\t\t\tonError={() => setFailed(true)}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'rounded-ui-lg max-h-full max-w-full object-contain shadow-2xl',\n\t\t\t\t\t\t\t'transition-transform duration-200 ease-out',\n\t\t\t\t\t\t\tentered ? 'scale-100' : 'scale-[0.97]'\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\t\t\t\t) : showsPdf ? (\n\t\t\t\t\t<iframe\n\t\t\t\t\t\tsrc={url}\n\t\t\t\t\t\ttitle={view.fileName ?? 'PDF'}\n\t\t\t\t\t\t// Best effort: a cross-origin 404 usually renders the\n\t\t\t\t\t\t// browser's own error page inside the frame and fires\n\t\t\t\t\t\t// `load`, so this catches only the cases it can.\n\t\t\t\t\t\tonError={() => setFailed(true)}\n\t\t\t\t\t\tclassName='rounded-ui-lg h-full w-full max-w-4xl bg-white shadow-2xl'\n\t\t\t\t\t/>\n\t\t\t\t) : (\n\t\t\t\t\t<div className={EMPTY_STATE_CLASS}>\n\t\t\t\t\t\t<span className='mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-white/5 text-white/70 ring-1 ring-white/10'>\n\t\t\t\t\t\t\t<FileWarningIcon className='h-8 w-8' />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<p className={EMPTY_TITLE_CLASS}>{copy.noPreview}</p>\n\t\t\t\t\t\t{view.fileName && (\n\t\t\t\t\t\t\t<p className='mt-3 max-w-full truncate font-mono text-[11px] text-white/40'>\n\t\t\t\t\t\t\t\t{view.fileName}\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\thref={url}\n\t\t\t\t\t\t\tdownload={view.fileName}\n\t\t\t\t\t\t\ttarget='_blank'\n\t\t\t\t\t\t\trel='noreferrer'\n\t\t\t\t\t\t\tclassName={cn(EMPTY_PRIMARY_CLASS, 'mt-5 inline-block')}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{copy.download(view.fileName ?? copy.filePreview)}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t</div>\n\n\t\t\t{/* Shortcut hints — pointless on touch, so fine pointers only. */}\n\t\t\t{!coarse && (\n\t\t\t\t<div\n\t\t\t\t\tclassName='flex items-center justify-center gap-4 pb-3 text-[11px] text-white/60'\n\t\t\t\t\tonClick={event => event.stopPropagation()}\n\t\t\t\t>\n\t\t\t\t\t<span className='flex items-center gap-1.5'>\n\t\t\t\t\t\t<Kbd>Esc</Kbd> {copy.close}\n\t\t\t\t\t</span>\n\t\t\t\t\t{url && (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<span className='flex items-center gap-1.5'>\n\t\t\t\t\t\t\t\t<Kbd>D</Kbd> {copy.downloadShort}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t<span className='flex items-center gap-1.5'>\n\t\t\t\t\t\t\t\t<Kbd>O</Kbd> {copy.openInTab}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</>\n\t\t\t\t\t)}\n\t\t\t\t\t{hasGallery && (\n\t\t\t\t\t\t<span className='flex items-center gap-1.5'>\n\t\t\t\t\t\t\t<Kbd>←</Kbd>\n\t\t\t\t\t\t\t<Kbd>→</Kbd> {copy.previous} / {copy.next}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>,\n\t\tdocument.body\n\t)\n}\n","import type { CompressOptions } from '../types'\n// Formats a canvas can re-encode. GIF would lose animation and SVG would\n// rasterize, so both pass through untouched.\nconst COMPRESSIBLE = new Set(['image/jpeg', 'image/png', 'image/webp'])\n\n/**\n * Client-side image trim before upload: downscale to the scope's box and\n * re-encode at the scope's quality. Re-encoding through a canvas drops EXIF as\n * a side effect — GPS and camera metadata never leave the device, regardless\n * of `stripExif` (a canvas cannot keep it).\n *\n * Falls back to the original file whenever it cannot help: non-compressible\n * formats, environments without `createImageBitmap`, decode failures, or a\n * \"compressed\" result that came out larger.\n */\nexport const compressImage = async (\n\tfile: File,\n\t{ maxWidth, maxHeight, quality = 0.8 }: CompressOptions\n): Promise<File> => {\n\tif (!COMPRESSIBLE.has(file.type)) return file\n\tif (typeof createImageBitmap !== 'function') return file\n\n\ttry {\n\t\tconst bitmap = await createImageBitmap(file)\n\t\tconst scale = Math.min(\n\t\t\t1,\n\t\t\t(maxWidth ?? Infinity) / bitmap.width,\n\t\t\t(maxHeight ?? Infinity) / bitmap.height\n\t\t)\n\n\t\tconst canvas = document.createElement('canvas')\n\t\tcanvas.width = Math.max(1, Math.round(bitmap.width * scale))\n\t\tcanvas.height = Math.max(1, Math.round(bitmap.height * scale))\n\t\tconst context = canvas.getContext('2d')\n\t\tif (!context) return file\n\t\tcontext.drawImage(bitmap, 0, 0, canvas.width, canvas.height)\n\t\tbitmap.close()\n\n\t\tconst blob = await new Promise<Blob | null>(resolve =>\n\t\t\tcanvas.toBlob(resolve, file.type, quality)\n\t\t)\n\t\tif (!blob || blob.size >= file.size) return file\n\n\t\treturn new File([blob], file.name, { type: file.type })\n\t} catch {\n\t\treturn file\n\t}\n}\n","import { getFileExtension } from '../file'\nimport type { FileExtension, StoredFile } from '../types'\n/** A named position a single file can fill (letterhead, CSF, acta, …). */\nexport type SlotDefinition = {\n\t/** Canonical id — becomes the stored file name (`{id}.{ext}`), so the\n\t * scope's `path` yields a stable key and re-uploads overwrite. */\n\tid: string\n\t/** Human label shown in the row. */\n\tlabel: string\n\t/** Lower-case extensions this slot takes. Narrower than the scope, never wider. */\n\textensions: FileExtension[]\n\thint?: string\n}\n\n/** A stored file tagged with the slot it fills. The app persists these. */\nexport type SlottedFile = {\n\tslot: string\n\tstored: StoredFile\n}\n\n/** Resolves which slot an incoming file belongs to, or `null` for none. */\nexport type SlotMatcher = (\n\tslots: SlotDefinition[],\n\tfileName: string\n) => string | null\n\n/**\n * Default matcher: the file's extension picks the slot. Prefers an empty slot\n * so dropping three files fills three positions; falls back to the first\n * extension match, which reads as \"replace what is there\".\n */\nexport const matchSlotByExtension =\n\t(filled: ReadonlySet<string>): SlotMatcher =>\n\t(slots, fileName) => {\n\t\tconst extension = getFileExtension(fileName) as FileExtension\n\t\tconst candidates = slots.filter(slot => slot.extensions.includes(extension))\n\t\tif (candidates.length === 0) return null\n\t\treturn (candidates.find(slot => !filled.has(slot.id)) ?? candidates[0]!).id\n\t}\n\n/** Matcher for uploads named after their slot (`letterhead-a4.pdf` → slot `letterhead-a4`). */\nexport const matchSlotByName: SlotMatcher = (slots, fileName) => {\n\tconst base = fileName.toLowerCase()\n\treturn slots.find(slot => base.startsWith(slot.id.toLowerCase()))?.id ?? null\n}\n\n/** The name a file adopts when it fills a slot. */\nexport const slotFileName = (slotId: string, originalName: string): string =>\n\t`${slotId}.${getFileExtension(originalName)}`\n\n/** The slot a stored file fills, recovered from its name. `null` when foreign. */\nexport const slotOfStored = (\n\tslots: SlotDefinition[],\n\tstored: StoredFile\n): string | null =>\n\tslots.find(slot => stored.fileName.startsWith(`${slot.id}.`))?.id ?? null\n","import { MAGIC_NUMBERS } from './constants'\nimport { formatFileSize, getFileExtension, isKnownExtension } from './file'\nimport { resolveLabels, type UploaderLabels } from './labels'\nimport type {\n\tFileExtension,\n\tFileLike,\n\tValidationOptions,\n\tValidationResult,\n} from './types'\n\nconst ok: ValidationResult = { valid: true }\n\nconst fail = (\n\tcode: Exclude<ValidationResult, { valid: true }>['code'],\n\tmessage: string\n): ValidationResult => ({ valid: false, code, message })\n\nexport const validateExtension = (\n\tfileName: string,\n\tallowed: FileExtension[],\n\tlabels?: Partial<UploaderLabels>\n): ValidationResult => {\n\tif (allowed.length === 0) return ok\n\n\tconst copy = resolveLabels(labels)\n\tconst extension = getFileExtension(fileName)\n\tif (!extension) {\n\t\treturn fail('extension-not-allowed', copy.fileHasNoExtension)\n\t}\n\tif (!allowed.includes(extension as FileExtension)) {\n\t\treturn fail('extension-not-allowed', copy.formatNotAllowed(allowed))\n\t}\n\treturn ok\n}\n\nexport const validateSize = (\n\tsize: number,\n\tmaxBytes: number,\n\tlabels?: Partial<UploaderLabels>\n): ValidationResult => {\n\tconst copy = resolveLabels(labels)\n\tif (size === 0) return fail('empty-file', copy.fileIsEmpty)\n\tif (size > maxBytes) {\n\t\treturn fail(\n\t\t\t'too-large',\n\t\t\tcopy.fileTooLarge(formatFileSize(size), formatFileSize(maxBytes))\n\t\t)\n\t}\n\treturn ok\n}\n\n/**\n * Compares the file's leading bytes against the signature its extension\n * claims. Extensions without a known signature pass — absence of a signature\n * is not evidence of tampering.\n */\nexport const validateMagicNumbers = async (\n\tfile: FileLike,\n\tlabels?: Partial<UploaderLabels>\n): Promise<ValidationResult> => {\n\tconst copy = resolveLabels(labels)\n\tconst extension = getFileExtension(file.name)\n\tif (!isKnownExtension(extension)) return ok\n\n\tconst expected = MAGIC_NUMBERS[extension]\n\tif (!expected) return ok\n\n\tconst head = new Uint8Array(await file.arrayBuffer()).slice(\n\t\t0,\n\t\texpected.length\n\t)\n\tif (head.length < expected.length) {\n\t\treturn fail('magic-number-mismatch', copy.fileIncomplete)\n\t}\n\n\tconst matches = expected.every((byte, index) => head[index] === byte)\n\treturn matches\n\t\t? ok\n\t\t: fail('magic-number-mismatch', copy.contentDoesNotMatchExtension)\n}\n\n/**\n * Runs the checks cheapest-first so a 2 GB file is rejected on its size before\n * anything reads its bytes.\n */\nexport const validateFile = async (\n\tfile: FileLike,\n\toptions: ValidationOptions = {}\n): Promise<ValidationResult> => {\n\tconst {\n\t\tmaxBytes = Infinity,\n\t\tallowedExtensions = [],\n\t\tvalidateMagicNumbers: checkMagic = false,\n\t\tlabels,\n\t\tcustomValidation,\n\t} = options\n\n\tconst size = validateSize(file.size, maxBytes, labels)\n\tif (!size.valid) return size\n\n\tconst extension = validateExtension(file.name, allowedExtensions, labels)\n\tif (!extension.valid) return extension\n\n\tif (checkMagic) {\n\t\tconst magic = await validateMagicNumbers(file, labels)\n\t\tif (!magic.valid) return magic\n\t}\n\n\tif (customValidation) return customValidation(file)\n\n\treturn ok\n}\n\nexport type FileValidation = {\n\tfile: FileLike\n\tresult: ValidationResult\n}\n\n/** Validates every file and reports each result; never short-circuits. */\nexport const validateFiles = async (\n\tfiles: FileLike[],\n\toptions: ValidationOptions = {}\n): Promise<FileValidation[]> =>\n\tPromise.all(\n\t\tfiles.map(async file => ({\n\t\t\tfile,\n\t\t\tresult: await validateFile(file, options),\n\t\t}))\n\t)\n","import { FILE_CATEGORY_CONFIG } from './constants'\nimport { toAcceptAttribute } from './file'\nimport type { UploaderLabels } from './labels'\nimport type {\n\tFileLike,\n\tReplaceMode,\n\tScopeConfig,\n\tScopeRegistry,\n\tStorageProvider,\n\tValidationResult,\n} from './types'\nimport { validateFile } from './validation'\n\n/** Thrown for a definition or wiring mistake — never for a user's bad file. */\nexport class ScopeError extends Error {\n\toverride name = 'ScopeError'\n}\n\n/** Stand-in entity used to compare the SHAPE of two `path` callbacks. */\nconst PROBE_ENTITY = '__entity__'\n\nconst probeFile = (name: string): FileLike => ({\n\tname,\n\tsize: 0,\n\ttype: '',\n\tarrayBuffer: async () => new ArrayBuffer(0),\n})\n\n/** True when `path` returns the same key whatever the file is called. */\nexport const hasStableKey = (scope: ScopeConfig): boolean =>\n\tscope.path(PROBE_ENTITY, probeFile('a.png')) ===\n\tscope.path(PROBE_ENTITY, probeFile('b.png'))\n\n/**\n * The mode a scope runs in when it does not name one.\n *\n * @see AGENTS.md §3 — why a stable key needs no sweep and a name-carrying one does\n */\nexport const resolveReplaceMode = (scope: ScopeConfig): ReplaceMode => {\n\tif (scope.replace !== undefined) return scope.replace\n\tif ((scope.maxFiles ?? 1) > 1) return 'key'\n\treturn hasStableKey(scope) ? 'key' : 'entity'\n}\n\nconst dirname = (key: string) => {\n\tconst cut = key.lastIndexOf('/')\n\treturn cut === -1 ? '' : key.slice(0, cut)\n}\n\n/** Folder an `'entity'` replace is allowed to sweep. */\nexport const resolveScopePrefix = (\n\tscope: ScopeConfig,\n\tentityId: string\n): string =>\n\tscope.prefix?.(entityId) ??\n\tdirname(scope.path(entityId, probeFile('probe.bin')))\n\n/** `a` contains `b`, counting only whole path segments. */\nconst containsPath = (a: string, b: string) => b === a || b.startsWith(`${a}/`)\n\nconst assertDefinition = (name: string, scope: ScopeConfig): void => {\n\tif (typeof scope.path !== 'function') {\n\t\tthrow new ScopeError(`Scope \"${name}\": \"path\" must be a function`)\n\t}\n\tif (!Number.isFinite(scope.maxBytes) || scope.maxBytes <= 0) {\n\t\tthrow new ScopeError(\n\t\t\t`Scope \"${name}\": \"maxBytes\" must be a positive number`\n\t\t)\n\t}\n\tif (scope.accept.length === 0) {\n\t\tthrow new ScopeError(\n\t\t\t`Scope \"${name}\": \"accept\" cannot be empty — list the extensions this scope takes`\n\t\t)\n\t}\n\n\t// A scope narrows its category, never widens it. Otherwise a 'pdf' scope\n\t// could quietly start taking executables.\n\tif (scope.category && scope.category !== 'any') {\n\t\tconst allowed = FILE_CATEGORY_CONFIG[scope.category].extensions\n\t\tconst outside = scope.accept.filter(\n\t\t\textension => !allowed.includes(extension)\n\t\t)\n\t\tif (outside.length > 0) {\n\t\t\tthrow new ScopeError(\n\t\t\t\t`Scope \"${name}\": ${outside.join(', ')} not allowed by category \"${scope.category}\"`\n\t\t\t)\n\t\t}\n\t}\n\n\tif (scope.compress) {\n\t\tconst imageOnly = FILE_CATEGORY_CONFIG.image.extensions\n\t\tconst notImages = scope.accept.filter(\n\t\t\textension => !imageOnly.includes(extension)\n\t\t)\n\t\tif (notImages.length > 0) {\n\t\t\tthrow new ScopeError(\n\t\t\t\t`Scope \"${name}\": \"compress\" only applies to images, but it accepts ${notImages.join(', ')}`\n\t\t\t)\n\t\t}\n\t}\n\n\tif (scope.maxFiles !== undefined) {\n\t\tif (!Number.isInteger(scope.maxFiles) || scope.maxFiles < 1) {\n\t\t\tthrow new ScopeError(\n\t\t\t\t`Scope \"${name}\": \"maxFiles\" must be a positive integer, received ${String(scope.maxFiles)}`\n\t\t\t)\n\t\t}\n\t}\n\n\t// The contradiction the derived default exists to prevent: a scope that\n\t// holds a collection cannot also erase the collection on every upload.\n\tif (scope.replace === 'entity' && (scope.maxFiles ?? 1) > 1) {\n\t\tthrow new ScopeError(\n\t\t\t`Scope \"${name}\": replace \"entity\" contradicts maxFiles ${scope.maxFiles} — ` +\n\t\t\t\t'an entity-wide replace would delete the other files on the next upload. ' +\n\t\t\t\t\"Use 'key' to overwrite one slot, or false to keep every version.\"\n\t\t)\n\t}\n\n\tif (\n\t\tresolveReplaceMode(scope) === 'entity' &&\n\t\tresolveScopePrefix(scope, PROBE_ENTITY) === ''\n\t) {\n\t\tthrow new ScopeError(\n\t\t\t`Scope \"${name}\": replace \"entity\" needs a folder to sweep, but \"path\" resolves to a ` +\n\t\t\t\t'bucket-root key. Nest the key under a folder, or declare \"prefix\".'\n\t\t)\n\t}\n}\n\n/**\n * Rejects a registry where sweeping one scope would reach another's objects.\n *\n * `path` shapes are compared through a placeholder entity, so this catches the\n * real hazard — two scopes sharing a folder for the SAME entity — while two\n * scopes rooted at different entity folders stay independent. A false positive\n * is answered with an explicit `prefix`, and the message says so.\n */\nconst assertNoSweepCollision = (scopes: Record<string, ScopeConfig>): void => {\n\tconst entries = Object.entries(scopes)\n\n\tfor (const [name, scope] of entries) {\n\t\tif (resolveReplaceMode(scope) !== 'entity') continue\n\t\tconst prefix = resolveScopePrefix(scope, PROBE_ENTITY)\n\n\t\tfor (const [otherName, other] of entries) {\n\t\t\tif (otherName === name) continue\n\t\t\tconst otherKey = other.path(PROBE_ENTITY, probeFile('probe.bin'))\n\t\t\tif (!containsPath(prefix, otherKey)) continue\n\n\t\t\tthrow new ScopeError(\n\t\t\t\t`Scope \"${name}\" replaces per entity and would sweep \"${prefix}\", which also holds ` +\n\t\t\t\t\t`scope \"${otherName}\" — an upload to one would delete the other's files. ` +\n\t\t\t\t\t'Give each its own folder, or declare a narrower \"prefix\".'\n\t\t\t)\n\t\t}\n\t}\n}\n\n/**\n * Declares every destination an app can write to. The returned registry is\n * imported by the client (to configure inputs and pre-validate) and by the\n * server (to authorize and re-validate), which is what keeps the two in sync.\n *\n * Definitions are checked eagerly: a malformed scope throws at import time,\n * not on the first upload. That includes the two replace mistakes no runtime\n * check could recover from — an entity-wide replace on a collection, and two\n * scopes whose folders overlap, where an avatar upload would delete the same\n * user's documents.\n */\nexport const defineScopes = <T extends Record<string, ScopeConfig>>(\n\tscopes: T\n): ScopeRegistry<T> => {\n\tfor (const [name, scope] of Object.entries(scopes)) {\n\t\tassertDefinition(name, scope)\n\t}\n\tassertNoSweepCollision(scopes)\n\n\tconst names = Object.keys(scopes) as (keyof T & string)[]\n\n\tconst get = (name: string): ScopeConfig => {\n\t\tconst scope = scopes[name as keyof T]\n\t\tif (!scope) {\n\t\t\tthrow new ScopeError(\n\t\t\t\t`Unknown scope \"${name}\". Declared: ${names.join(', ')}`\n\t\t\t)\n\t\t}\n\t\treturn scope\n\t}\n\n\treturn {\n\t\tscopes,\n\t\tnames,\n\t\tget,\n\t\thas: name => name in scopes,\n\t\taccept: name => toAcceptAttribute(get(name).accept),\n\t}\n}\n\n/**\n * The one validation call. Client runs it for feedback, server runs it for\n * safety, both against the same scope.\n *\n * `labels` is what keeps the two answers identical in wording as well as in\n * verdict: the hook passes the copy it renders with, `createStorage` passes\n * the copy it was configured with.\n */\nexport const validateForScope = async <T extends Record<string, ScopeConfig>>(\n\tregistry: ScopeRegistry<T>,\n\tname: string,\n\tfile: FileLike,\n\tlabels?: Partial<UploaderLabels>\n): Promise<ValidationResult> => {\n\tconst scope = registry.get(name)\n\tconst category = scope.category\n\t\t? FILE_CATEGORY_CONFIG[scope.category]\n\t\t: undefined\n\n\treturn validateFile(file, {\n\t\tmaxBytes: scope.maxBytes,\n\t\tallowedExtensions: scope.accept,\n\t\tvalidateMagicNumbers: category?.validateMagicNumbers ?? true,\n\t\tlabels,\n\t})\n}\n\n/**\n * Fails fast when a provider cannot honour what the scopes promise — a private\n * scope on a provider that cannot sign URLs is a runtime 403 waiting to happen.\n */\nexport const assertProviderSupports = <T extends Record<string, ScopeConfig>>(\n\tregistry: ScopeRegistry<T>,\n\tprovider: StorageProvider\n): void => {\n\tconst needsSigning = registry.names.filter(\n\t\tname => registry.get(name).visibility === 'private'\n\t)\n\n\tif (needsSigning.length > 0 && !provider.capabilities.signedUrl) {\n\t\tthrow new ScopeError(\n\t\t\t`Provider \"${provider.name}\" cannot sign URLs, but these scopes are private: ${needsSigning.join(', ')}`\n\t\t)\n\t}\n}\n\n/**\n * Whether a key would escape its own prefix.\n *\n * Judged per SEGMENT. A `key.includes('..')` test reads as the same check and\n * is not: `report..pdf` and `Screenshot at 4.18.54 p.m..png` carry two dots\n * without ever being traversal, and a macOS screenshot is the common case, not\n * a corner one. Traversal needs a segment that IS `..`, so that is what this\n * asks.\n */\nconst escapesPrefix = (key: string): boolean =>\n\tkey.startsWith('/') ||\n\tkey.split('/').some(segment => segment === '..' || segment === '.')\n\n/**\n * Resolves the storage key for an upload.\n *\n * The guard is a backstop, not a sanitizer: it refuses a key rather than\n * rewriting one, because a client computing the same key to decide replace\n * mode would then disagree with the server. Run {@link sanitizeFileName}\n * inside the scope's `path()` and both sides stay identical.\n */\nexport const resolveKey = <T extends Record<string, ScopeConfig>>(\n\tregistry: ScopeRegistry<T>,\n\tname: string,\n\tentityId: string,\n\tfile: FileLike\n): string => {\n\tconst key = registry.get(name).path(entityId, file)\n\tif (escapesPrefix(key)) {\n\t\tthrow new ScopeError(`Scope \"${name}\" produced an unsafe key: ${key}`)\n\t}\n\treturn key\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nimport type { UploaderLabels } from '../labels'\nimport { validateForScope } from '../scopes'\nimport type { ScopeConfig, ScopeRegistry } from '../types'\nimport type { StoredFile } from '../types'\nimport { warnDev } from '../warn'\nimport { compressImage } from './compressImage'\nimport type { UploaderFile, UploadStrategy } from './types'\nimport { useUploaderLabels } from './UploaderProvider'\n\n/**\n * When the machine sends: `'manual'` holds files in `idle` until the app calls\n * `upload()` — the form-submit flow, where the file travels together with the\n * rest of the fields' action. `'select'` fires as soon as a valid file lands.\n */\nexport type UploadTrigger = 'select' | 'manual'\n\nexport type RetryOptions = {\n\t/** Total attempts per file, the first one included. @defaultValue 1 */\n\tattempts?: number\n\t/** Delay before the first retry; doubles on each further one. @defaultValue 500 */\n\tbackoffMs?: number\n}\n\nexport type UseUploaderOptions<T extends Record<string, ScopeConfig>> = {\n\t/** The app's registry — the same object the server authorizes against. */\n\tscopes: ScopeRegistry<T>\n\tscope: keyof T & string\n\t/** Owner of the uploads (customerId, userId, …), forwarded to the strategy. */\n\tentityId: string\n\t/** Transport. Omit for local-only selection + validation (no `upload`). */\n\tstrategy?: UploadStrategy\n\t/**\n\t * Overrides the arity derived from the scope's `maxFiles`. Rarely needed:\n\t * the registry is what the server validates against.\n\t */\n\tmultiple?: boolean\n\t/** Overrides the scope's own `maxFiles`, downward. */\n\tmaxFiles?: number\n\t/** @defaultValue 'manual' — the styled `Uploader` flips it to `'select'`. */\n\tuploadOn?: UploadTrigger\n\t/**\n\t * Fired when a batch actually starts travelling — from either trigger — with\n\t * the files it carries. The place to flip a form into its \"sending\" state.\n\t */\n\tonUploadStart?: (files: UploaderFile[]) => void\n\t/** Fired once per batch with the files the server confirmed. */\n\tonUploaded?: (stored: StoredFile[]) => void\n\tonError?: (message: string) => void\n\t/**\n\t * Re-run a failed strategy call before surfacing the error. A number is\n\t * shorthand for `{ attempts }`. Aborts never retry, and validation failures\n\t * never reach the strategy in the first place.\n\t */\n\tretry?: number | RetryOptions\n\t/** Max uploads in flight per batch; the rest queue. @defaultValue Infinity */\n\tconcurrency?: number\n\t/**\n\t * Rename each file before it enters the machine — a client-side input, a\n\t * folio, a slug. Runs before validation, so a rename that changes the\n\t * extension is rejected like any other invalid file. The stored key comes\n\t * from the scope's `path(entityId, file)`, which reads this name.\n\t */\n\trename?: (file: File) => string\n\tlabels?: Partial<UploaderLabels>\n}\n\nexport type UseUploaderReturn = {\n\tfiles: UploaderFile[]\n\t/** Ready-made value for `<input accept>`, derived from the scope. */\n\taccept: string\n\tisUploading: boolean\n\t/** `true` while any file waits in `idle` — a manual trigger has work to do. */\n\thasPending: boolean\n\taddFiles: (incoming: FileList | File[]) => Promise<void>\n\t/** Uploads every file still in `idle`. Resolves with the confirmed ones. */\n\tupload: () => Promise<StoredFile[]>\n\t/** Abort one in-flight upload, or all of them when no id is given. */\n\tabort: (id?: string) => void\n\tremoveFile: (id: string) => void\n\tclear: () => void\n}\n\nconst createId = () =>\n\ttypeof crypto !== 'undefined' && 'randomUUID' in crypto\n\t\t? crypto.randomUUID()\n\t\t: Math.random().toString(36).slice(2)\n\nconst previewOf = (file: File): string | undefined =>\n\tfile.type.startsWith('image/') &&\n\ttypeof URL !== 'undefined' &&\n\ttypeof URL.createObjectURL === 'function'\n\t\t? URL.createObjectURL(file)\n\t\t: undefined\n\nconst revokePreview = (file: UploaderFile) => {\n\tif (file.preview) URL.revokeObjectURL(file.preview)\n}\n\nconst normalizeRetry = (retry: number | RetryOptions | undefined) => {\n\tconst options =\n\t\ttypeof retry === 'number' ? { attempts: retry } : (retry ?? {})\n\treturn {\n\t\tattempts: Math.max(1, options.attempts ?? 1),\n\t\tbackoffMs: options.backoffMs ?? 500,\n\t}\n}\n\n/** Abortable sleep: the backoff between retries must die with the upload. */\nconst wait = (ms: number, signal: AbortSignal) =>\n\tnew Promise<void>((resolve, reject) => {\n\t\tconst abort = () => {\n\t\t\tclearTimeout(timer)\n\t\t\tconst error = new Error('Upload cancelled')\n\t\t\terror.name = 'AbortError'\n\t\t\treject(error)\n\t\t}\n\t\tconst timer = setTimeout(() => {\n\t\t\tsignal.removeEventListener('abort', abort)\n\t\t\tresolve()\n\t\t}, ms)\n\t\tsignal.addEventListener('abort', abort, { once: true })\n\t})\n\n/**\n * Run `run` over every item with at most `limit` in flight. Order of results\n * matches the input; a settled slot immediately frees a worker for the next.\n */\nconst runPool = async <T, R>(\n\titems: T[],\n\tlimit: number,\n\trun: (item: T) => Promise<R>\n): Promise<R[]> => {\n\tconst results = new Array<R>(items.length)\n\tlet cursor = 0\n\tconst workers = Array.from(\n\t\t{ length: Math.min(Math.max(1, limit), items.length) },\n\t\tasync () => {\n\t\t\twhile (cursor < items.length) {\n\t\t\t\tconst index = cursor++\n\t\t\t\tresults[index] = await run(items[index]!)\n\t\t\t}\n\t\t}\n\t)\n\tawait Promise.all(workers)\n\treturn results\n}\n\n/**\n * Headless upload state machine: selection → validation → (compression) →\n * upload with progress and abort. Owns no markup — render `files` however the\n * screen needs and wire `addFiles` to an input or a drop zone.\n *\n * Validation runs here with the same `validateForScope` the server runs, so\n * the user sees the rejection before any byte leaves the machine.\n */\nexport const useUploader = <T extends Record<string, ScopeConfig>>({\n\tscopes,\n\tscope,\n\tentityId,\n\tstrategy,\n\tmultiple: multipleOption,\n\tmaxFiles: maxFilesOption,\n\tuploadOn = 'manual',\n\tonUploadStart,\n\tonUploaded,\n\tonError,\n\tretry,\n\tconcurrency = Infinity,\n\trename,\n\tlabels,\n}: UseUploaderOptions<T>): UseUploaderReturn => {\n\t// Derived from the registry, never from the call site — see AGENTS.md §3.\n\t// The props stay as a narrowing override.\n\tconst scopeMaxFiles = scopes.get(scope).maxFiles\n\tconst maxFiles = maxFilesOption ?? scopeMaxFiles\n\tconst multiple = multipleOption ?? (maxFiles !== undefined && maxFiles > 1)\n\n\tconst [files, setFiles] = useState<UploaderFile[]>([])\n\tconst controllers = useRef(new Map<string, AbortController>())\n\t// Kept in a ref so `addFiles` → auto-upload reads the batch it just built,\n\t// not the state snapshot from before the setFiles commit.\n\tconst filesRef = useRef<UploaderFile[]>([])\n\tfilesRef.current = files\n\tconst copy = useUploaderLabels(labels)\n\tconst { attempts, backoffMs } = normalizeRetry(retry)\n\n\tconst patch = useCallback((id: string, changes: Partial<UploaderFile>) => {\n\t\tsetFiles(previous =>\n\t\t\tprevious.map(file => (file.id === id ? { ...file, ...changes } : file))\n\t\t)\n\t}, [])\n\n\tconst uploadOne = useCallback(\n\t\tasync (target: UploaderFile): Promise<StoredFile | null> => {\n\t\t\tif (!strategy) {\n\t\t\t\twarnDev(\n\t\t\t\t\t'upload-without-strategy',\n\t\t\t\t\t'upload() ran without a `strategy` — files stay local. Pass `strategy` (e.g. createXhrUploadStrategy) to useUploader.'\n\t\t\t\t)\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst config = scopes.get(scope)\n\n\t\t\tconst controller = new AbortController()\n\t\t\tcontrollers.current.set(target.id, controller)\n\t\t\tpatch(target.id, { status: 'uploading', progress: 0 })\n\n\t\t\ttry {\n\t\t\t\tconst payload = config.compress\n\t\t\t\t\t? await compressImage(target.file, config.compress)\n\t\t\t\t\t: target.file\n\n\t\t\t\t// Compression runs once; only the transport retries.\n\t\t\t\tfor (let attempt = 1; ; attempt++) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst stored = await strategy(payload, scope, entityId, {\n\t\t\t\t\t\t\tonProgress: percent => patch(target.id, { progress: percent }),\n\t\t\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\t\t})\n\t\t\t\t\t\tpatch(target.id, { status: 'success', progress: 100, stored })\n\t\t\t\t\t\treturn stored\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tconst aborted =\n\t\t\t\t\t\t\terror instanceof Error && error.name === 'AbortError'\n\t\t\t\t\t\tif (aborted || attempt >= attempts) throw error\n\t\t\t\t\t\tpatch(target.id, { progress: 0 })\n\t\t\t\t\t\tawait wait(backoffMs * 2 ** (attempt - 1), controller.signal)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst aborted = error instanceof Error && error.name === 'AbortError'\n\t\t\t\tconst message =\n\t\t\t\t\terror instanceof Error && error.message\n\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t: copy.uploadFailed\n\t\t\t\tpatch(target.id, {\n\t\t\t\t\tstatus: aborted ? 'idle' : 'error',\n\t\t\t\t\tprogress: 0,\n\t\t\t\t\t...(aborted ? {} : { error: message }),\n\t\t\t\t})\n\t\t\t\tif (!aborted) onError?.(message)\n\t\t\t\treturn null\n\t\t\t} finally {\n\t\t\t\tcontrollers.current.delete(target.id)\n\t\t\t}\n\t\t},\n\t\t[\n\t\t\tstrategy,\n\t\t\tscopes,\n\t\t\tscope,\n\t\t\tentityId,\n\t\t\tpatch,\n\t\t\tonError,\n\t\t\tattempts,\n\t\t\tbackoffMs,\n\t\t\tcopy,\n\t\t]\n\t)\n\n\tconst uploadBatch = useCallback(\n\t\tasync (targets: UploaderFile[]): Promise<StoredFile[]> => {\n\t\t\tif (targets.length === 0) return []\n\t\t\tonUploadStart?.(targets)\n\t\t\tconst results = await runPool(targets, concurrency, uploadOne)\n\t\t\tconst stored = results.filter((r): r is StoredFile => r !== null)\n\t\t\tif (stored.length > 0) onUploaded?.(stored)\n\t\t\treturn stored\n\t\t},\n\t\t[uploadOne, onUploadStart, onUploaded, concurrency]\n\t)\n\n\tconst addFiles = useCallback(\n\t\tasync (incoming: FileList | File[]) => {\n\t\t\tlet batch = Array.from(incoming)\n\t\t\tif (!multiple && batch.length > 1) {\n\t\t\t\twarnDev(\n\t\t\t\t\t'single-mode-multi-drop',\n\t\t\t\t\t`addFiles received ${batch.length} files but \\`multiple\\` is false — only the first is kept. Pass multiple: true if that is not what you meant.`\n\t\t\t\t)\n\t\t\t}\n\t\t\tif (!multiple) batch = batch.slice(0, 1)\n\n\t\t\tif (maxFiles !== undefined) {\n\t\t\t\tconst room = maxFiles - (multiple ? filesRef.current.length : 0)\n\t\t\t\tif (batch.length > room) {\n\t\t\t\t\tbatch = batch.slice(0, Math.max(0, room))\n\t\t\t\t\tonError?.(copy.maxFilesReached(maxFiles))\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (batch.length === 0) return\n\n\t\t\tif (rename) {\n\t\t\t\tbatch = batch.map(\n\t\t\t\t\tfile => new File([file], rename(file), { type: file.type })\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tconst next: UploaderFile[] = []\n\t\t\tfor (const file of batch) {\n\t\t\t\tconst result = await validateForScope(scopes, scope, file, copy)\n\t\t\t\tnext.push({\n\t\t\t\t\tid: createId(),\n\t\t\t\t\tfile,\n\t\t\t\t\tstatus: result.valid ? 'idle' : 'error',\n\t\t\t\t\tprogress: 0,\n\t\t\t\t\t...(result.valid\n\t\t\t\t\t\t? { preview: previewOf(file) }\n\t\t\t\t\t\t: { error: result.message }),\n\t\t\t\t})\n\t\t\t\tif (!result.valid) onError?.(next[next.length - 1]!.error!)\n\t\t\t}\n\n\t\t\tsetFiles(previous => {\n\t\t\t\tif (multiple) return [...previous, ...next]\n\t\t\t\tprevious.forEach(revokePreview)\n\t\t\t\treturn next\n\t\t\t})\n\n\t\t\tif (uploadOn === 'select') {\n\t\t\t\tawait uploadBatch(next.filter(file => file.status === 'idle'))\n\t\t\t}\n\t\t},\n\t\t[\n\t\t\tmultiple,\n\t\t\tmaxFiles,\n\t\t\tscopes,\n\t\t\tscope,\n\t\t\tuploadOn,\n\t\t\tuploadBatch,\n\t\t\tonError,\n\t\t\trename,\n\t\t\tcopy,\n\t\t]\n\t)\n\n\tconst upload = useCallback(\n\t\t() => uploadBatch(filesRef.current.filter(f => f.status === 'idle')),\n\t\t[uploadBatch]\n\t)\n\n\tconst abort = useCallback((id?: string) => {\n\t\tif (id) {\n\t\t\tcontrollers.current.get(id)?.abort()\n\t\t\treturn\n\t\t}\n\t\tcontrollers.current.forEach(controller => controller.abort())\n\t}, [])\n\n\tconst removeFile = useCallback(\n\t\t(id: string) => {\n\t\t\tabort(id)\n\t\t\tsetFiles(previous => {\n\t\t\t\tconst target = previous.find(file => file.id === id)\n\t\t\t\tif (target) revokePreview(target)\n\t\t\t\treturn previous.filter(file => file.id !== id)\n\t\t\t})\n\t\t},\n\t\t[abort]\n\t)\n\n\tconst clear = useCallback(() => {\n\t\tabort()\n\t\tsetFiles(previous => {\n\t\t\tprevious.forEach(revokePreview)\n\t\t\treturn []\n\t\t})\n\t}, [abort])\n\n\t// Object URLs leak until revoked; the unmount sweep catches whatever the\n\t// screen never removed explicitly.\n\tuseEffect(\n\t\t() => () => {\n\t\t\tfilesRef.current.forEach(revokePreview)\n\t\t\tcontrollers.current.forEach(controller => controller.abort())\n\t\t},\n\t\t[]\n\t)\n\n\tconst accept = useMemo(() => scopes.accept(scope), [scopes, scope])\n\n\treturn {\n\t\tfiles,\n\t\taccept,\n\t\tisUploading: files.some(file => file.status === 'uploading'),\n\t\thasPending: files.some(file => file.status === 'idle'),\n\t\taddFiles,\n\t\tupload,\n\t\tabort,\n\t\tremoveFile,\n\t\tclear,\n\t}\n}\n","import { useCallback, useMemo, useRef } from 'react'\n\nimport { getFileExtension, toAcceptAttribute } from '../file'\nimport type { UploaderLabels } from '../labels'\nimport { resolveReplaceMode } from '../scopes'\nimport { ScopeError } from '../scopes'\nimport type { ScopeConfig, ScopeRegistry } from '../types'\nimport type { FileExtension } from '../types'\nimport { warnDev } from '../warn'\nimport {\n\tmatchSlotByExtension,\n\tmatchSlotByName,\n\ttype SlotDefinition,\n\tslotFileName,\n\ttype SlotMatcher,\n\ttype SlottedFile,\n} from './slots'\nimport type { RemoveStrategy, UploaderFile, UploadStrategy } from './types'\nimport { useUploaderLabels } from './UploaderProvider'\nimport {\n\ttype RetryOptions,\n\ttype UploadTrigger,\n\tuseUploader,\n} from './useUploader'\n\nexport type UseSlottedUploaderOptions<T extends Record<string, ScopeConfig>> = {\n\tscopes: ScopeRegistry<T>\n\tscope: keyof T & string\n\tentityId: string\n\tstrategy?: UploadStrategy\n\t/**\n\t * Deletion transport. With it, a confirmed `removeSlot` deletes the object\n\t * from storage BY ITSELF — unless the scope is `keepOnRemove`, the history\n\t * contract — so no consumer can orphan by forgetting a callback.\n\t * `onRemoveStored` still fires for the app's own bookkeeping.\n\t */\n\tremoveStrategy?: RemoveStrategy\n\tslots: SlotDefinition[]\n\t/** Currently persisted files. The caller owns persistence — controlled. */\n\tvalue: SlottedFile[]\n\t/** Called with the next full set after an upload lands or a slot empties. */\n\tonChange: (next: SlottedFile[]) => void | Promise<void>\n\t/** How dropped files find their slot. @defaultValue 'extension' */\n\tmatchBy?: 'extension' | 'name'\n\t/** Custom matcher for special rules; overrides `matchBy`. */\n\tmatch?: SlotMatcher\n\t/** @defaultValue 'select' — a slot names its file, so it usually travels at once. */\n\tuploadOn?: UploadTrigger\n\t/** Fired when a batch starts travelling. Same contract as `useUploader`. */\n\tonUploadStart?: (files: UploaderFile[]) => void\n\t/**\n\t * Fired with the PERSISTED file a `removeSlot` just forgot, before\n\t * `onChange` delivers the filtered set. This is where the app deletes the\n\t * object from storage — without it the consumer had to diff old-vs-new\n\t * arrays to even learn which key vanished, and every stable-key scope\n\t * orphaned on remove.\n\t */\n\tonRemoveStored?: (stored: SlottedFile) => void\n\tonError?: (message: string) => void\n\t/** Forwarded to the underlying `useUploader`. */\n\tretry?: number | RetryOptions\n\t/** Forwarded to the underlying `useUploader`. */\n\tconcurrency?: number\n\tlabels?: Partial<UploaderLabels>\n}\n\nexport type SlotState = {\n\tdefinition: SlotDefinition\n\t/** Persisted file occupying the slot, if any. */\n\tfilled?: SlottedFile\n\t/** In-flight or failed upload for the slot, if any. */\n\tpending?: UploaderFile\n}\n\nexport type UseSlottedUploaderReturn = {\n\tslots: SlotState[]\n\t/** `<input accept>` derived from the union of the slots' extensions. */\n\taccept: string\n\tisUploading: boolean\n\t/** Route a dropped/browsed batch to slots via the matcher. */\n\taddFiles: (incoming: FileList | File[]) => Promise<void>\n\t/** Put one file in one specific slot (per-row browse button). */\n\taddToSlot: (slotId: string, file: File) => Promise<void>\n\t/**\n\t * Forget the persisted file of a slot. Remote deletion stays the app's\n\t * call — made through `onRemoveStored`, which receives the forgotten file.\n\t */\n\tremoveSlot: (slotId: string) => void\n\tabort: (slotId?: string) => void\n\t/** Uploads every slot still holding an `idle` file (`uploadOn: 'manual'`). */\n\tupload: () => Promise<void>\n\t/** `true` while any slot holds an `idle` file waiting for `upload()`. */\n\thasPending: boolean\n}\n\n/**\n * Named-slot collection over the SAME machine as the plain uploader: this hook\n * only decides *which slot* a file lands in and renames it to `{slot}.{ext}`;\n * validation, compression, progress and abort are `useUploader` verbatim. One\n * behavior, two presentations — a fix in the machine reaches both.\n */\nexport const useSlottedUploader = <T extends Record<string, ScopeConfig>>({\n\tscopes,\n\tscope,\n\tentityId,\n\tstrategy,\n\tslots,\n\tvalue,\n\tonChange,\n\tmatchBy = 'extension',\n\tmatch,\n\tuploadOn = 'select',\n\tonUploadStart,\n\tremoveStrategy,\n\tonRemoveStored,\n\tonError,\n\tretry,\n\tconcurrency,\n\tlabels,\n}: UseSlottedUploaderOptions<T>): UseSlottedUploaderReturn => {\n\tconst copy = useUploaderLabels(labels)\n\t// Impossible configs throw, \"will fail at upload time\" configs warn once.\n\t// See AGENTS.md §3.1.\n\tuseMemo(() => {\n\t\tconst ids = new Set<string>()\n\t\tfor (const slot of slots) {\n\t\t\tif (ids.has(slot.id)) {\n\t\t\t\tthrow new ScopeError(\n\t\t\t\t\t`useSlottedUploader: duplicate slot id \"${slot.id}\" — slot ids are storage keys and must be unique`\n\t\t\t\t)\n\t\t\t}\n\t\t\tids.add(slot.id)\n\t\t}\n\t\t// A slot per position means the scope holds several files at once, so a\n\t\t// sweep would delete the sibling slots on every upload — silently, and\n\t\t// only in production. Same tier as a duplicate slot id: it can never\n\t\t// work, so it fails at import.\n\t\tif (\n\t\t\tslots.length > 1 &&\n\t\t\tresolveReplaceMode(scopes.get(scope)) === 'entity'\n\t\t) {\n\t\t\tthrow new ScopeError(\n\t\t\t\t`useSlottedUploader: scope \"${scope}\" replaces per entity, so filling one of its ` +\n\t\t\t\t\t`${slots.length} slots would delete the others. Declare \"maxFiles\" on the scope ` +\n\t\t\t\t\t\"(one per slot, at least), or set replace: 'key'.\"\n\t\t\t)\n\t\t}\n\n\t\tconst accepted = scopes.get(scope).accept\n\t\tfor (const slot of slots) {\n\t\t\tconst outside = slot.extensions.filter(\n\t\t\t\textension => !accepted.includes(extension)\n\t\t\t)\n\t\t\tif (outside.length > 0) {\n\t\t\t\twarnDev(\n\t\t\t\t\t`slot-outside-scope:${slot.id}`,\n\t\t\t\t\t`slot \"${slot.id}\" accepts ${outside.join(', ')} but scope \"${scope}\" does not — those uploads will be rejected by validation. Align the slot's extensions with the scope's accept list.`\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}, [slots, scopes, scope])\n\n\t// Latest persisted set, readable from inside onUploaded without re-binding\n\t// the uploader callbacks on every render.\n\tconst valueRef = useRef(value)\n\tvalueRef.current = value\n\tconst onChangeRef = useRef(onChange)\n\tonChangeRef.current = onChange\n\n\t// Uploads the parent has not absorbed into `value` yet. Two quick drops\n\t// would otherwise race the controlled state: the second onChange reads a\n\t// `value` that misses the first drop's entry and silently loses it.\n\tconst landedRef = useRef(new Map<string, SlottedFile>())\n\tfor (const [slot, item] of landedRef.current) {\n\t\tconst absorbed = value.some(\n\t\t\tentry =>\n\t\t\t\tentry.slot === slot &&\n\t\t\t\tentry.stored.key === item.stored.key &&\n\t\t\t\tentry.stored.uploadedAt === item.stored.uploadedAt\n\t\t)\n\t\tif (absorbed) landedRef.current.delete(slot)\n\t}\n\n\tconst uploader = useUploader({\n\t\tscopes,\n\t\tscope,\n\t\tentityId,\n\t\tstrategy,\n\t\tmultiple: true,\n\t\tuploadOn,\n\t\tonUploadStart,\n\t\tonError,\n\t\t...(retry !== undefined ? { retry } : {}),\n\t\t...(concurrency !== undefined ? { concurrency } : {}),\n\t\t...(labels ? { labels } : {}),\n\t\tonUploaded: stored => {\n\t\t\t// Files were renamed to `{slot}.{ext}` before entering the machine, so\n\t\t\t// the slot is recoverable from the confirmed name.\n\t\t\tfor (const item of stored) {\n\t\t\t\tconst slot = slots.find(s => item.fileName.startsWith(`${s.id}.`))\n\t\t\t\tif (slot)\n\t\t\t\t\tlandedRef.current.set(slot.id, { slot: slot.id, stored: item })\n\t\t\t}\n\t\t\tconst merged = new Map(valueRef.current.map(entry => [entry.slot, entry]))\n\t\t\tlandedRef.current.forEach((entry, slot) => merged.set(slot, entry))\n\t\t\tvoid onChangeRef.current([...merged.values()])\n\t\t},\n\t})\n\n\tconst resolveSlot = useMemo<SlotMatcher>(() => {\n\t\tif (match) return match\n\t\tif (matchBy === 'name') return matchSlotByName\n\t\treturn (all, fileName) =>\n\t\t\tmatchSlotByExtension(new Set(valueRef.current.map(item => item.slot)))(\n\t\t\t\tall,\n\t\t\t\tfileName\n\t\t\t)\n\t}, [match, matchBy])\n\n\t// Renames a file after its slot, or reports why it cannot fill it.\n\tconst assign = useCallback(\n\t\t(slotId: string, file: File): File | null => {\n\t\t\tconst slot = slots.find(s => s.id === slotId)\n\t\t\tif (!slot) return null\n\n\t\t\tconst extension = getFileExtension(file.name) as FileExtension\n\t\t\tif (!slot.extensions.includes(extension)) {\n\t\t\t\tonError?.(copy.slotFormatNotAllowed(slot.label, slot.extensions))\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn new File([file], slotFileName(slotId, file.name), {\n\t\t\t\ttype: file.type,\n\t\t\t})\n\t\t},\n\t\t[slots, onError, copy]\n\t)\n\n\tconst addToSlot = useCallback(\n\t\tasync (slotId: string, file: File) => {\n\t\t\tconst renamed = assign(slotId, file)\n\t\t\tif (renamed) await uploader.addFiles([renamed])\n\t\t},\n\t\t[assign, uploader]\n\t)\n\n\tconst addFiles = useCallback(\n\t\tasync (incoming: FileList | File[]) => {\n\t\t\t// One batch for the whole drop: a single onUploaded → a single\n\t\t\t// onChange carrying every slot that landed.\n\t\t\tconst batch: File[] = []\n\t\t\tfor (const file of Array.from(incoming)) {\n\t\t\t\tconst slotId = resolveSlot(slots, file.name)\n\t\t\t\tif (!slotId) {\n\t\t\t\t\tonError?.(copy.fileWithoutSlot(file.name))\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst renamed = assign(slotId, file)\n\t\t\t\tif (renamed) batch.push(renamed)\n\t\t\t}\n\t\t\tif (batch.length > 0) await uploader.addFiles(batch)\n\t\t},\n\t\t[slots, resolveSlot, assign, uploader, onError, copy]\n\t)\n\n\tconst removeSlot = useCallback(\n\t\t(slotId: string) => {\n\t\t\t// Drop any in-flight attempt for the slot too, or a slow upload would\n\t\t\t// resurrect the file the user just removed.\n\t\t\tuploader.files\n\t\t\t\t.filter(file => file.file.name.startsWith(`${slotId}.`))\n\t\t\t\t.forEach(file => uploader.removeFile(file.id))\n\t\t\tlandedRef.current.delete(slotId)\n\t\t\tconst forgotten = valueRef.current.find(item => item.slot === slotId)\n\t\t\tif (forgotten) {\n\t\t\t\t// The package deletes; the app only observes. Fire-and-forget\n\t\t\t\t// with the reference ordering: forget the reference regardless,\n\t\t\t\t// because a dangling pointer is worse than an orphan — and\n\t\t\t\t// surface a refused delete instead of swallowing it.\n\t\t\t\tif (removeStrategy && !scopes.get(scope).keepOnRemove) {\n\t\t\t\t\tremoveStrategy(forgotten.stored, scope, entityId)\n\t\t\t\t\t\t.then(deleted => {\n\t\t\t\t\t\t\tif (!deleted) onError?.(copy.removeFailed)\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch(() => onError?.(copy.removeFailed))\n\t\t\t\t}\n\t\t\t\tonRemoveStored?.(forgotten)\n\t\t\t}\n\t\t\tvoid onChangeRef.current(\n\t\t\t\tvalueRef.current.filter(item => item.slot !== slotId)\n\t\t\t)\n\t\t},\n\t\t[\n\t\t\tuploader,\n\t\t\tremoveStrategy,\n\t\t\tscopes,\n\t\t\tscope,\n\t\t\tentityId,\n\t\t\tonRemoveStored,\n\t\t\tonError,\n\t\t\tcopy,\n\t\t]\n\t)\n\n\tconst abort = useCallback(\n\t\t(slotId?: string) => {\n\t\t\tif (!slotId) {\n\t\t\t\tuploader.abort()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tuploader.files\n\t\t\t\t.filter(file => file.file.name.startsWith(`${slotId}.`))\n\t\t\t\t.forEach(file => uploader.abort(file.id))\n\t\t},\n\t\t[uploader]\n\t)\n\n\tconst slotStates = useMemo<SlotState[]>(\n\t\t() =>\n\t\t\tslots.map(definition => ({\n\t\t\t\tdefinition,\n\t\t\t\tfilled: value.find(item => item.slot === definition.id),\n\t\t\t\tpending: uploader.files.find(\n\t\t\t\t\tfile =>\n\t\t\t\t\t\tfile.file.name.startsWith(`${definition.id}.`) &&\n\t\t\t\t\t\tfile.status !== 'success'\n\t\t\t\t),\n\t\t\t})),\n\t\t[slots, value, uploader.files]\n\t)\n\n\tconst accept = useMemo(\n\t\t() => toAcceptAttribute([...new Set(slots.flatMap(s => s.extensions))]),\n\t\t[slots]\n\t)\n\n\tconst upload = useCallback(async () => {\n\t\tawait uploader.upload()\n\t}, [uploader])\n\n\treturn {\n\t\tslots: slotStates,\n\t\taccept,\n\t\tisUploading: uploader.isUploading,\n\t\thasPending: uploader.hasPending,\n\t\taddFiles,\n\t\taddToSlot,\n\t\tremoveSlot,\n\t\tabort,\n\t\tupload,\n\t}\n}\n","import { type DragEvent, useRef, useState } from 'react'\n\nimport { formatFileSize } from '../file'\nimport type { UploaderLabels } from '../labels'\nimport type { SlotState } from '../react'\nimport { useUploaderLabels } from '../react/UploaderProvider'\nimport { cn } from './cn'\nimport { FileTypeBadge } from './FileTypeBadge'\nimport { ProgressBar } from './ProgressBar'\n\nexport type SlotRowProps = {\n\tslot: SlotState\n\t/** Fill this one slot from its own browse button. */\n\tonPick: (file: File) => void\n\tonRemove: () => void\n\tonAbort: () => void\n\tonView: () => void\n\t/** @defaultValue 'md' */\n\tsize?: 'sm' | 'md'\n\tlabels?: Partial<UploaderLabels>\n}\n\n/**\n * One named position of a `SlottedUploader`: a status dot, a thumbnail, the\n * slot's label, whatever occupies it, and the actions for that state.\n *\n * @remarks\n * Four occupancies, not two: under `uploadOn: 'submit'` a picked file waits at\n * `idle` in `pending` with no `filled`, and a row branching on `filled` alone\n * rendered it as an empty slot — with no way to undo the pick.\n */\nexport const SlotRow = ({\n\tslot,\n\tonPick,\n\tonRemove,\n\tonAbort,\n\tonView,\n\tsize = 'md',\n\tlabels,\n}: SlotRowProps) => {\n\tconst copy = useUploaderLabels(labels)\n\tconst inputRef = useRef<HTMLInputElement>(null)\n\tconst [dropping, setDropping] = useState(false)\n\t// Depth counter — see Dropzone.\n\tconst depth = useRef(0)\n\tconst { definition, filled, pending } = slot\n\tconst uploading = pending?.status === 'uploading'\n\t/** Picked but not sent yet — the `uploadOn: 'submit'` resting state. */\n\tconst staged = pending?.status === 'idle'\n\tconst occupied = Boolean(filled) || staged\n\tconst droppable = !uploading\n\n\t// The row itself is a drop target: dragging a file over a filled slot\n\t// reads as \"replace this one\", over an empty one as \"fill it\" — no trip\n\t// through the bulk zone and its matcher.\n\tconst onDrop = (event: DragEvent) => {\n\t\tevent.preventDefault()\n\t\tevent.stopPropagation()\n\t\tdepth.current = 0\n\t\tsetDropping(false)\n\t\tif (!droppable) return\n\t\tconst file = event.dataTransfer.files[0]\n\t\tif (file) onPick(file)\n\t}\n\n\tconst action =\n\t\t'focus-visible:ring-ui-ring rounded-ui shrink-0 cursor-pointer px-2 py-1 text-xs transition-colors focus-visible:ring-2 focus-visible:outline-none'\n\n\treturn (\n\t\t<div\n\t\t\tonDragEnter={() => {\n\t\t\t\tdepth.current += 1\n\t\t\t\tif (droppable) setDropping(true)\n\t\t\t}}\n\t\t\tonDragOver={event => {\n\t\t\t\tevent.preventDefault()\n\t\t\t\tevent.stopPropagation()\n\t\t\t}}\n\t\t\tonDragLeave={() => {\n\t\t\t\tdepth.current = Math.max(0, depth.current - 1)\n\t\t\t\tif (depth.current === 0) setDropping(false)\n\t\t\t}}\n\t\t\tonDrop={onDrop}\n\t\t\tclassName={cn(\n\t\t\t\t'rounded-ui animate-ui-fade-in flex items-center gap-3 border text-sm transition-all duration-200',\n\t\t\t\tsize === 'sm' ? 'p-1.5' : 'p-2',\n\t\t\t\tdropping\n\t\t\t\t\t? 'border-ui-primary bg-ui-primary-soft ring-ui-ring scale-[1.01] ring-2'\n\t\t\t\t\t: 'border-ui-border'\n\t\t\t)}\n\t\t>\n\t\t\t<span\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'h-2.5 w-2.5 shrink-0 rounded-full transition-colors',\n\t\t\t\t\tpending?.status === 'error'\n\t\t\t\t\t\t? 'bg-ui-danger'\n\t\t\t\t\t\t: uploading\n\t\t\t\t\t\t\t? 'bg-ui-primary animate-pulse'\n\t\t\t\t\t\t\t: staged\n\t\t\t\t\t\t\t\t? 'bg-ui-warning'\n\t\t\t\t\t\t\t\t: filled\n\t\t\t\t\t\t\t\t\t? 'bg-ui-success'\n\t\t\t\t\t\t\t\t\t: 'bg-ui-border-strong'\n\t\t\t\t)}\n\t\t\t/>\n\n\t\t\t{/* Reserved in every state, so picking a file does not change the\n\t\t\t row's height. */}\n\t\t\t<FileTypeBadge\n\t\t\t\tfileName={pending?.file.name ?? filled?.stored.fileName}\n\t\t\t\tpreview={pending?.preview}\n\t\t\t\tsize={size}\n\t\t\t/>\n\n\t\t\t<div className='min-w-0 flex-1'>\n\t\t\t\t<p className='text-ui-fg truncate font-medium'>{definition.label}</p>\n\t\t\t\t{pending?.status === 'error' ? (\n\t\t\t\t\t<p className='text-ui-danger text-xs'>{pending.error}</p>\n\t\t\t\t) : pending ? (\n\t\t\t\t\t// The name is the STORAGE one: `assign` renames the pick to\n\t\t\t\t\t// `{slot}.{ext}` before it reaches the machine.\n\t\t\t\t\t<p className='text-ui-muted truncate text-xs'>\n\t\t\t\t\t\t{pending.file.name} · {formatFileSize(pending.file.size)}\n\t\t\t\t\t\t{staged && ` · ${copy.staged}`}\n\t\t\t\t\t</p>\n\t\t\t\t) : filled ? (\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype='button'\n\t\t\t\t\t\tonClick={onView}\n\t\t\t\t\t\tclassName='text-ui-muted hover:text-ui-primary block max-w-full cursor-pointer truncate text-left text-xs hover:underline'\n\t\t\t\t\t>\n\t\t\t\t\t\t{filled.stored.fileName}\n\t\t\t\t\t</button>\n\t\t\t\t) : (\n\t\t\t\t\t<p className='text-ui-placeholder text-xs'>\n\t\t\t\t\t\t{definition.hint ??\n\t\t\t\t\t\t\tdefinition.extensions.map(e => `.${e}`).join(' · ')}\n\t\t\t\t\t</p>\n\t\t\t\t)}\n\t\t\t\t{uploading && <ProgressBar percent={pending.progress} />}\n\t\t\t</div>\n\n\t\t\t<input\n\t\t\t\tref={inputRef}\n\t\t\t\ttype='file'\n\t\t\t\taccept={definition.extensions.map(e => `.${e}`).join(',')}\n\t\t\t\tclassName='hidden'\n\t\t\t\tonChange={event => {\n\t\t\t\t\tconst file = event.target.files?.[0]\n\t\t\t\t\tif (file) onPick(file)\n\t\t\t\t\tevent.target.value = ''\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t{dropping && (\n\t\t\t\t<span className='bg-ui-primary text-ui-primary-fg rounded-full px-2.5 py-1 text-[11px] font-medium whitespace-nowrap'>\n\t\t\t\t\t{occupied ? copy.dropToReplace : copy.upload}\n\t\t\t\t</span>\n\t\t\t)}\n\t\t\t{!dropping && filled && !uploading && (\n\t\t\t\t<button\n\t\t\t\t\ttype='button'\n\t\t\t\t\tonClick={onView}\n\t\t\t\t\tclassName={cn(action, 'text-ui-primary hover:bg-ui-primary-soft')}\n\t\t\t\t>\n\t\t\t\t\t{copy.view}\n\t\t\t\t</button>\n\t\t\t)}\n\t\t\t{uploading ? (\n\t\t\t\t<button\n\t\t\t\t\ttype='button'\n\t\t\t\t\tonClick={onAbort}\n\t\t\t\t\tclassName={cn(action, 'text-ui-muted hover:bg-ui-surface-muted')}\n\t\t\t\t>\n\t\t\t\t\t{copy.cancel}\n\t\t\t\t</button>\n\t\t\t) : dropping ? null : (\n\t\t\t\t<>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype='button'\n\t\t\t\t\t\tonClick={() => inputRef.current?.click()}\n\t\t\t\t\t\tclassName={cn(action, 'text-ui-primary hover:bg-ui-primary-soft')}\n\t\t\t\t\t>\n\t\t\t\t\t\t{occupied ? copy.replace : copy.upload}\n\t\t\t\t\t</button>\n\t\t\t\t\t{occupied && (\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype='button'\n\t\t\t\t\t\t\tonClick={onRemove}\n\t\t\t\t\t\t\tclassName={cn(action, 'text-ui-muted hover:bg-ui-surface-muted')}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{copy.remove}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t)}\n\t\t\t\t</>\n\t\t\t)}\n\t\t</div>\n\t)\n}\n","import { useCallback, useMemo, useState } from 'react'\n\nimport type { FileViewerProps, ViewableFile } from './FileViewer'\n\nexport type UseFileViewerOptions = {\n\t/** Forwarded to the viewer — the authenticated resolver for private urls. */\n\tresolveUrl?: FileViewerProps['resolveUrl']\n}\n\nexport type UseFileViewerReturn = {\n\t/** Currently open file, `null` when closed. */\n\tviewing: ViewableFile | null\n\topen: (file: ViewableFile) => void\n\tclose: () => void\n\t/** Spread into `<FileViewer {...viewerProps} />` — the whole wiring. */\n\tviewerProps: Pick<FileViewerProps, 'file' | 'onClose' | 'resolveUrl'>\n}\n\n/**\n * The open/close state every screen with a `FileViewer` repeats. One call\n * replaces the `useState` + prop plumbing:\n *\n * ```tsx\n * const viewer = useFileViewer({ resolveUrl })\n * <button onClick={() => viewer.open(stored)}>Ver</button>\n * <FileViewer {...viewer.viewerProps} />\n * ```\n */\nexport const useFileViewer = ({\n\tresolveUrl,\n}: UseFileViewerOptions = {}): UseFileViewerReturn => {\n\tconst [viewing, setViewing] = useState<ViewableFile | null>(null)\n\tconst close = useCallback(() => setViewing(null), [])\n\tconst open = useCallback((file: ViewableFile) => setViewing(file), [])\n\n\treturn {\n\t\tviewing,\n\t\topen,\n\t\tclose,\n\t\tviewerProps: useMemo(\n\t\t\t() => ({ file: viewing, onClose: close, resolveUrl }),\n\t\t\t[viewing, close, resolveUrl]\n\t\t),\n\t}\n}\n","import { type ReactNode, useEffect, useState } from 'react'\n\nimport type { SlotState, UseSlottedUploaderOptions } from '../react'\nimport { useSlottedUploader } from '../react'\nimport type { RemoveStrategy } from '../react/types'\nimport { useUploaderLabels } from '../react/UploaderProvider'\nimport type { ScopeConfig } from '../types'\nimport { warnDev } from '../warn'\nimport { cn } from './cn'\nimport { ConfirmDialog } from './ConfirmDialog'\nimport type { UiUploadTrigger, UploaderControllerRef } from './controller'\nimport { Dropzone } from './Dropzone'\nimport { FileViewer, type ViewableFile } from './FileViewer'\nimport { UploadCloudIcon } from './icons'\nimport { SlotRow } from './SlotRow'\nimport { useCoarsePointer } from './useCoarsePointer'\nimport { useFileViewer } from './useFileViewer'\n\n/** A pending second step: the user asked for it, the dialog decides. */\ntype PendingAction =\n\t| { kind: 'remove'; slot: SlotState }\n\t| { kind: 'replace'; slot: SlotState; file: File }\n\nexport type SlottedUploaderProps<T extends Record<string, ScopeConfig>> = Omit<\n\tUseSlottedUploaderOptions<T>,\n\t'uploadOn'\n> & {\n\t/**\n\t * When the slots travel. This presentation has no upload button of its\n\t * own, so `'manual'` is not offered here: staged slots can only leave\n\t * through a form's `controllerRef`, which is `'submit'`.\n\t * @defaultValue 'select'\n\t * @see UiUploadTrigger\n\t */\n\tuploadOn?: Exclude<UiUploadTrigger, 'manual'>\n\ttitle?: string\n\tdescription?: string\n\t/** Hide the bulk dropzone and keep only per-row buttons. */\n\thideDropzone?: boolean\n\t/**\n\t * Gate removing a filled slot behind a confirmation dialog. `true` uses\n\t * the label defaults; an object overrides the copy.\n\t */\n\tconfirmRemove?: boolean | { title?: string; message?: string }\n\t/**\n\t * Confirm before a picked file replaces what a slot already holds. The\n\t * dialog names both files, so the user sees what is about to be lost.\n\t */\n\tconfirmReplace?: boolean | { title?: string; message?: string }\n\t/**\n\t * Deletion transport. With it, a confirmed slot removal deletes the object\n\t * from storage BY ITSELF — unless the scope is `keepOnRemove`, the history\n\t * contract — same wiring as `Uploader`.\n\t */\n\tremoveStrategy?: RemoveStrategy\n\t/** Fresh URL right before previewing — for private scopes whose signed url expired. */\n\tresolveViewUrl?: (file: ViewableFile) => Promise<string>\n\t/** Compact paddings and glyphs everywhere. @defaultValue 'md' */\n\tsize?: 'sm' | 'md'\n\t/** Glyph inside the bulk dropzone. `null` removes it. */\n\ticon?: ReactNode\n\t/** Keyboard shortcut that opens the bulk picker, e.g. `'mod+u'`. */\n\tshortcut?: string\n\t/**\n\t * Filled with the live controller so the surrounding form can send the\n\t * staged slots from its own submit. Required by `uploadOn: 'submit'`:\n\t * without it a staged slot has no way to ever leave.\n\t */\n\tcontrollerRef?: UploaderControllerRef<void>\n\t/**\n\t * Fires when the zone starts or stops holding files that `upload()`\n\t * would send. The companion of `controllerRef`: a form that defers the\n\t * send has no other way to know it has unsent work, so its save button\n\t * would stay disabled on a pristine form the user has just dropped a\n\t * file into.\n\t */\n\tonPendingChange?: (hasPending: boolean) => void\n\tclassName?: string\n}\n\n/**\n * Named-slot presentation over the same machine as `Uploader`: a status row\n * per slot plus one bulk dropzone whose matcher routes each file to its slot.\n */\nexport const SlottedUploader = <T extends Record<string, ScopeConfig>>({\n\tuploadOn = 'select',\n\ttitle,\n\tdescription,\n\thideDropzone = false,\n\tconfirmRemove,\n\tconfirmReplace,\n\tremoveStrategy,\n\tresolveViewUrl,\n\tsize = 'md',\n\ticon,\n\tshortcut,\n\tcontrollerRef,\n\tonPendingChange,\n\tclassName,\n\t...options\n}: SlottedUploaderProps<T>) => {\n\tconst slotted = useSlottedUploader({\n\t\t...options,\n\t\tuploadOn: uploadOn === 'select' ? 'select' : 'manual',\n\t})\n\n\tif (uploadOn === 'submit' && !controllerRef) {\n\t\twarnDev(\n\t\t\t'slotted-submit-without-controller',\n\t\t\t\"uploadOn: 'submit' has no send of its own here — pass `controllerRef` and call upload() from the form's submit, or staged slots never leave.\"\n\t\t)\n\t}\n\tconst copy = useUploaderLabels(options.labels)\n\tconst coarse = useCoarsePointer()\n\tconst viewer = useFileViewer({ resolveUrl: resolveViewUrl })\n\tconst [pending, setPending] = useState<PendingAction | null>(null)\n\n\tconst { upload, hasPending, isUploading } = slotted\n\tuseEffect(() => {\n\t\tif (!controllerRef) return\n\t\tcontrollerRef.current = { upload, hasPending, isUploading }\n\t\treturn () => {\n\t\t\tcontrollerRef.current = null\n\t\t}\n\t}, [controllerRef, upload, hasPending, isUploading])\n\n\tuseEffect(() => {\n\t\tonPendingChange?.(hasPending)\n\t}, [onPendingChange, hasPending])\n\n\tconst pick = (slot: SlotState, file: File) => {\n\t\tif (slot.filled && confirmReplace) {\n\t\t\tsetPending({ kind: 'replace', slot, file })\n\t\t\treturn\n\t\t}\n\t\tvoid slotted.addToSlot(slot.definition.id, file)\n\t}\n\n\t// Same contract as Uploader's forgetStored: the package deletes, the app\n\t// observes, and the reference is forgotten even when the delete fails.\n\tconst forgetSlot = (slot: SlotState) => {\n\t\tconst stored = slot.filled?.stored\n\t\tif (\n\t\t\tstored &&\n\t\t\tremoveStrategy &&\n\t\t\t!options.scopes.get(options.scope).keepOnRemove\n\t\t) {\n\t\t\tremoveStrategy(stored, options.scope, options.entityId)\n\t\t\t\t.then(deleted => {\n\t\t\t\t\tif (!deleted) options.onError?.(copy.removeFailed)\n\t\t\t\t})\n\t\t\t\t.catch(() => options.onError?.(copy.removeFailed))\n\t\t}\n\t\tslotted.removeSlot(slot.definition.id)\n\t}\n\n\tconst remove = (slot: SlotState) => {\n\t\tif (slot.filled && confirmRemove) {\n\t\t\tsetPending({ kind: 'remove', slot })\n\t\t\treturn\n\t\t}\n\t\tforgetSlot(slot)\n\t}\n\n\tconst override =\n\t\tpending?.kind === 'replace'\n\t\t\t? typeof confirmReplace === 'object'\n\t\t\t\t? confirmReplace\n\t\t\t\t: {}\n\t\t\t: typeof confirmRemove === 'object'\n\t\t\t\t? confirmRemove\n\t\t\t\t: {}\n\n\tconst dialogTitle =\n\t\toverride.title ??\n\t\t(pending?.kind === 'replace'\n\t\t\t? copy.confirmReplaceTitle\n\t\t\t: copy.confirmRemoveTitle)\n\tconst dialogMessage =\n\t\toverride.message ??\n\t\t(pending?.kind === 'replace'\n\t\t\t? copy.confirmReplaceMessage(\n\t\t\t\t\tpending.slot.filled?.stored.fileName ?? '',\n\t\t\t\t\tpending.file.name\n\t\t\t\t)\n\t\t\t: copy.confirmRemoveMessage(pending?.slot.filled?.stored.fileName ?? ''))\n\n\treturn (\n\t\t<div className={cn('space-y-2', className)}>\n\t\t\t{title && <p className='text-ui-fg text-sm font-medium'>{title}</p>}\n\t\t\t{description && <p className='text-ui-muted text-xs'>{description}</p>}\n\n\t\t\t{slotted.slots.map(slot => (\n\t\t\t\t<SlotRow\n\t\t\t\t\tkey={slot.definition.id}\n\t\t\t\t\tslot={slot}\n\t\t\t\t\tonPick={file => pick(slot, file)}\n\t\t\t\t\tonRemove={() => remove(slot)}\n\t\t\t\t\tonAbort={() => slotted.abort(slot.definition.id)}\n\t\t\t\t\tonView={() => slot.filled && viewer.open(slot.filled.stored)}\n\t\t\t\t\tsize={size}\n\t\t\t\t\tlabels={options.labels}\n\t\t\t\t/>\n\t\t\t))}\n\n\t\t\t{!hideDropzone && (\n\t\t\t\t<Dropzone\n\t\t\t\t\taccept={slotted.accept}\n\t\t\t\t\tmultiple\n\t\t\t\t\tdisabled={slotted.isUploading}\n\t\t\t\t\tsize={size}\n\t\t\t\t\tshortcut={shortcut}\n\t\t\t\t\tonFiles={files => void slotted.addFiles(files)}\n\t\t\t\t>\n\t\t\t\t\t{icon !== null && (\n\t\t\t\t\t\t<span className='text-ui-placeholder group-hover/dz:text-ui-primary group-data-dragging/dz:text-ui-primary mb-1.5 inline-flex justify-center transition-all duration-200 group-hover/dz:-translate-y-0.5 group-data-dragging/dz:-translate-y-1 group-data-dragging/dz:scale-110'>\n\t\t\t\t\t\t\t{icon ?? (\n\t\t\t\t\t\t\t\t<UploadCloudIcon\n\t\t\t\t\t\t\t\t\tclassName={size === 'sm' ? 'h-5 w-5' : 'h-7 w-7'}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t)}\n\t\t\t\t\t<p className='text-ui-muted group-hover/dz:text-ui-fg text-sm font-medium transition-colors duration-200'>\n\t\t\t\t\t\t{coarse ? copy.bulkTapPrompt : copy.bulkDropPrompt}\n\t\t\t\t\t</p>\n\t\t\t\t</Dropzone>\n\t\t\t)}\n\n\t\t\t<FileViewer {...viewer.viewerProps} labels={options.labels} />\n\n\t\t\t<ConfirmDialog\n\t\t\t\topen={pending !== null}\n\t\t\t\ttitle={dialogTitle}\n\t\t\t\tmessage={dialogMessage}\n\t\t\t\tonConfirm={() => {\n\t\t\t\t\tif (pending?.kind === 'replace') {\n\t\t\t\t\t\tvoid slotted.addToSlot(pending.slot.definition.id, pending.file)\n\t\t\t\t\t} else if (pending) {\n\t\t\t\t\t\tforgetSlot(pending.slot)\n\t\t\t\t\t}\n\t\t\t\t\tsetPending(null)\n\t\t\t\t}}\n\t\t\t\tonCancel={() => setPending(null)}\n\t\t\t\tlabels={options.labels}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n","import { formatFileSize } from '../file'\nimport type { UploaderLabels } from '../labels'\nimport { useUploaderLabels } from '../react/UploaderProvider'\nimport type { StoredFile } from '../types'\nimport { cn } from './cn'\nimport { FileTypeBadge } from './FileTypeBadge'\n\nexport type StoredFileItemProps = {\n\tfile: StoredFile\n\tonView: () => void\n\t/** Omitted when the screen does not let the user detach a persisted file. */\n\tonRemove?: (file: StoredFile) => void\n\t/** @defaultValue 'md' */\n\tsize?: 'sm' | 'md'\n\tlabels?: Partial<UploaderLabels>\n}\n\n/**\n * One row for a file the app has already persisted: extension chip, name,\n * size, and the actions to preview or forget it. The settled counterpart of\n * `FileItem`, which tracks a file that is still going through the machine.\n */\nexport const StoredFileItem = ({\n\tfile,\n\tonView,\n\tonRemove,\n\tsize = 'md',\n\tlabels,\n}: StoredFileItemProps) => {\n\tconst copy = useUploaderLabels(labels)\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'border-ui-border bg-ui-surface-subtle rounded-ui animate-ui-fade-in flex items-center gap-3 border text-sm',\n\t\t\t\tsize === 'sm' ? 'p-1.5' : 'p-2'\n\t\t\t)}\n\t\t>\n\t\t\t<FileTypeBadge fileName={file.fileName} size={size} />\n\n\t\t\t<div className='min-w-0 flex-1'>\n\t\t\t\t<p className='text-ui-fg truncate font-medium'>{file.fileName}</p>\n\t\t\t\t<p className='text-ui-muted text-xs'>{formatFileSize(file.size)}</p>\n\t\t\t</div>\n\n\t\t\t<button\n\t\t\t\ttype='button'\n\t\t\t\tonClick={onView}\n\t\t\t\tclassName='text-ui-primary hover:bg-ui-primary-soft focus-visible:ring-ui-ring rounded-ui shrink-0 cursor-pointer px-2 py-1 text-xs transition-colors focus-visible:ring-2 focus-visible:outline-none'\n\t\t\t>\n\t\t\t\t{copy.view}\n\t\t\t</button>\n\t\t\t{onRemove && (\n\t\t\t\t<button\n\t\t\t\t\ttype='button'\n\t\t\t\t\tonClick={() => onRemove(file)}\n\t\t\t\t\tclassName='text-ui-muted hover:bg-ui-surface-muted hover:text-ui-fg focus-visible:ring-ui-ring rounded-ui shrink-0 cursor-pointer px-2 py-1 text-xs transition-colors focus-visible:ring-2 focus-visible:outline-none'\n\t\t\t\t>\n\t\t\t\t\t{copy.remove}\n\t\t\t\t</button>\n\t\t\t)}\n\t\t</div>\n\t)\n}\n","import { type ReactNode, useEffect, useState } from 'react'\n\nimport type { UseUploaderOptions } from '../react'\nimport { useUploader } from '../react'\nimport type { RemoveStrategy, UploaderFile } from '../react/types'\nimport { useUploaderLabels } from '../react/UploaderProvider'\nimport type { ScopeConfig } from '../types'\nimport type { StoredFile } from '../types'\nimport { warnDev } from '../warn'\nimport { cn } from './cn'\nimport { ConfirmDialog } from './ConfirmDialog'\nimport type { UiUploadTrigger, UploaderControllerRef } from './controller'\nimport { Dropzone } from './Dropzone'\nimport { FileItem } from './FileItem'\nimport { FileViewer, type ViewableFile } from './FileViewer'\nimport { UploadCloudIcon } from './icons'\nimport { StoredFileItem } from './StoredFileItem'\nimport { useCoarsePointer } from './useCoarsePointer'\nimport { useFileViewer } from './useFileViewer'\n\n/**\n * What {@link UploaderProps.renderFiles} is handed.\n *\n * Both the raw state and the default rows already built, so a custom layout can\n * keep the standard item and only change where — and among what — it sits.\n */\nexport type UploaderFilesSlot = {\n\t/** Files already persisted, exactly as passed in `stored`. */\n\tstored: StoredFile[]\n\t/** Files staged in this session, each with its live upload status. */\n\tstaged: UploaderFile[]\n\t/** The default rows. Place them, wrap them, or drop them entirely. */\n\tnodes: ReactNode\n\t/** Nothing persisted and nothing staged. */\n\tisEmpty: boolean\n\t/** Open a persisted file in the built-in viewer. */\n\tview: (file: StoredFile) => void\n\t/** Forget a staged file. */\n\tremove: (id: string) => void\n\t/**\n\t * Forget a persisted file, honouring `confirmRemove` and `removeStrategy`.\n\t * `undefined` when this uploader accepts no removals.\n\t */\n\tremoveStored?: (file: StoredFile) => void\n}\n\nexport type UploaderProps<T extends Record<string, ScopeConfig>> = Omit<\n\tUseUploaderOptions<T>,\n\t'uploadOn'\n> & {\n\t/**\n\t * When the files travel. @defaultValue 'select'\n\t * @see UiUploadTrigger — which mode fits which screen\n\t */\n\tuploadOn?: UiUploadTrigger\n\tlabel?: string\n\tdescription?: string\n\t/** Files already persisted, rendered on the {@link filesPosition} side. */\n\tstored?: StoredFile[]\n\t/**\n\t * Which side of the dropzone the file lists sit on. @defaultValue 'above'\n\t *\n\t * `'below'` keeps the drop target anchored: with the lists above it, every\n\t * added file pushes the zone further down, so the control the user is\n\t * repeatedly aiming at moves under the cursor.\n\t */\n\tfilesPosition?: 'above' | 'below'\n\t/**\n\t * Lay the file lists out yourself: a grid of thumbnails, a single summary\n\t * line, a count folded into your own card — whatever the screen needs.\n\t *\n\t * It replaces the rows, not their place: the result still renders on the\n\t * {@link filesPosition} side. For a layout the zone itself has to be part of\n\t * (files BESIDE the dropzone, files inside your own frame), skip this skin\n\t * and compose `useUploader` with the exported `Dropzone` / `FileItem` /\n\t * `StoredFileItem` — nothing here is unavailable there.\n\t */\n\trenderFiles?: (slot: UploaderFilesSlot) => ReactNode\n\t/**\n\t * Notified when a persisted file is forgotten — the app's bookkeeping\n\t * (clear the DB reference). Storage deletion belongs to `removeStrategy`.\n\t */\n\tonRemoveStored?: (file: StoredFile) => void\n\t/**\n\t * Deletion transport. With it, a confirmed removal deletes the object from\n\t * storage BY ITSELF — unless the scope is `keepOnRemove`, the history\n\t * contract — so no consumer can orphan by forgetting a callback.\n\t */\n\tremoveStrategy?: RemoveStrategy\n\t/**\n\t * Gate `onRemoveStored` behind a confirmation dialog. `true` uses the\n\t * label defaults; an object overrides the copy for this uploader.\n\t */\n\tconfirmRemove?: boolean | { title?: string; message?: string }\n\t/** Fresh URL right before previewing — for private scopes whose signed url expired. */\n\tresolveViewUrl?: (file: ViewableFile) => Promise<string>\n\t/** Mobile camera shortcut, forwarded to the dropzone's input. */\n\tcapture?: 'user' | 'environment'\n\t/** Compact paddings and glyphs everywhere. @defaultValue 'md' */\n\tsize?: 'sm' | 'md'\n\t/** Glyph inside the dropzone. `null` removes it; defaults to an upload cloud. */\n\ticon?: ReactNode\n\t/** Keyboard shortcut that opens the picker, e.g. `'mod+u'`. Hinted in the zone. */\n\tshortcut?: string\n\t/**\n\t * Filled with the live controller so the surrounding form can send the\n\t * staged files from its own submit. Required by `uploadOn: 'submit'`,\n\t * which has no other way to fire; readable under `'manual'` too, where\n\t * the zone's button stays the sender.\n\t */\n\tcontrollerRef?: UploaderControllerRef\n\t/**\n\t * Fires when the zone starts or stops holding files that `upload()`\n\t * would send. The companion of `controllerRef`: a form that defers the\n\t * send has no other way to know it has unsent work, so its save button\n\t * would stay disabled on a pristine form the user has just dropped a\n\t * file into.\n\t */\n\tonPendingChange?: (hasPending: boolean) => void\n\tdisabled?: boolean\n\tclassName?: string\n}\n\n/**\n * The styled single-zone uploader: one dropzone, one or many files in it.\n * Purely a skin over `useUploader` — apps needing custom markup use the hook\n * directly and lose nothing.\n *\n * Defaults `uploadOn` to `'select'`. `'manual'` gives the zone its own upload\n * button; `'submit'` hands the send to the surrounding form via\n * `controllerRef`. @see UiUploadTrigger for which mode fits which screen.\n */\nexport const Uploader = <T extends Record<string, ScopeConfig>>({\n\tuploadOn = 'select',\n\tlabel,\n\tdescription,\n\tstored = [],\n\tfilesPosition = 'above',\n\trenderFiles,\n\tonRemoveStored,\n\tconfirmRemove,\n\tresolveViewUrl,\n\tcapture,\n\tsize = 'md',\n\ticon,\n\tshortcut,\n\tcontrollerRef,\n\tonPendingChange,\n\tremoveStrategy,\n\tdisabled = false,\n\tclassName,\n\t...options\n}: UploaderProps<T>) => {\n\t// 'submit' and 'manual' are the same hook state; who calls upload() differs.\n\tconst uploader = useUploader({\n\t\t...options,\n\t\tuploadOn: uploadOn === 'select' ? 'select' : 'manual',\n\t})\n\tconst copy = useUploaderLabels(options.labels)\n\tconst viewer = useFileViewer({ resolveUrl: resolveViewUrl })\n\tconst [removing, setRemoving] = useState<StoredFile | null>(null)\n\tconst { files, removeFile } = uploader\n\t// Only 'manual' renders the zone's button: under 'submit' the form owns the\n\t// send, and a second, unvalidated way to fire the same batch is one too many.\n\tconst manual = uploadOn === 'manual'\n\n\tif (uploadOn === 'submit' && !controllerRef) {\n\t\twarnDev(\n\t\t\t'uploader-submit-without-controller',\n\t\t\t\"uploadOn: 'submit' has no send of its own — pass `controllerRef` and call upload() from the form's submit, or use 'manual' for the zone's button.\"\n\t\t)\n\t}\n\t// Touch-first devices barely drag; the zone reads as a tap target there.\n\tconst coarse = useCoarsePointer()\n\n\t// Once the app echoes an upload back through `stored`, the machine's copy\n\t// would render the file twice. Depends on the two members it reads, never\n\t// on `uploader` — that object is fresh on every render.\n\tuseEffect(() => {\n\t\tif (stored.length === 0) return\n\t\tconst keys = new Set(stored.map(file => file.key))\n\t\tfiles\n\t\t\t.filter(f => f.status === 'success' && f.stored && keys.has(f.stored.key))\n\t\t\t.forEach(f => removeFile(f.id))\n\t}, [stored, files, removeFile])\n\n\tconst { upload, hasPending, isUploading } = uploader\n\tuseEffect(() => {\n\t\tif (!controllerRef) return\n\t\tcontrollerRef.current = { upload, hasPending, isUploading }\n\t\treturn () => {\n\t\t\tcontrollerRef.current = null\n\t\t}\n\t}, [controllerRef, upload, hasPending, isUploading])\n\n\tuseEffect(() => {\n\t\tonPendingChange?.(hasPending)\n\t}, [onPendingChange, hasPending])\n\n\t// One forget path for both branches: the package deletes, the app observes.\n\t// The reference is forgotten regardless — a dangling pointer is worse than\n\t// an orphan — and a refused delete surfaces through `onError`.\n\tconst forgetStored = (file: StoredFile) => {\n\t\tif (removeStrategy && !options.scopes.get(options.scope).keepOnRemove) {\n\t\t\tremoveStrategy(file, options.scope, options.entityId)\n\t\t\t\t.then(deleted => {\n\t\t\t\t\tif (!deleted) options.onError?.(copy.removeFailed)\n\t\t\t\t})\n\t\t\t\t.catch(() => options.onError?.(copy.removeFailed))\n\t\t}\n\t\tonRemoveStored?.(file)\n\t}\n\n\tconst requestRemove =\n\t\tonRemoveStored || removeStrategy\n\t\t\t? (file: StoredFile) =>\n\t\t\t\t\tconfirmRemove ? setRemoving(file) : forgetStored(file)\n\t\t\t: undefined\n\n\tconst confirmCopy = typeof confirmRemove === 'object' ? confirmRemove : {}\n\n\tconst defaultRows = (\n\t\t<>\n\t\t\t{stored.map(file => (\n\t\t\t\t<StoredFileItem\n\t\t\t\t\tkey={file.key}\n\t\t\t\t\tfile={file}\n\t\t\t\t\tonView={() => viewer.open(file)}\n\t\t\t\t\tonRemove={requestRemove}\n\t\t\t\t\tsize={size}\n\t\t\t\t\tlabels={options.labels}\n\t\t\t\t/>\n\t\t\t))}\n\n\t\t\t{files.map(file => {\n\t\t\t\tconst { stored: settled } = file\n\t\t\t\treturn (\n\t\t\t\t\t<FileItem\n\t\t\t\t\t\tkey={file.id}\n\t\t\t\t\t\tfile={file}\n\t\t\t\t\t\tonRemove={() => removeFile(file.id)}\n\t\t\t\t\t\tonAbort={() => uploader.abort(file.id)}\n\t\t\t\t\t\tonView={settled ? () => viewer.open(settled) : undefined}\n\t\t\t\t\t\tsize={size}\n\t\t\t\t\t\tlabels={options.labels}\n\t\t\t\t\t/>\n\t\t\t\t)\n\t\t\t})}\n\t\t</>\n\t)\n\n\tconst fileList = renderFiles\n\t\t? renderFiles({\n\t\t\t\tstored,\n\t\t\t\tstaged: files,\n\t\t\t\tnodes: defaultRows,\n\t\t\t\tisEmpty: stored.length === 0 && files.length === 0,\n\t\t\t\tview: viewer.open,\n\t\t\t\tremove: removeFile,\n\t\t\t\tremoveStored: requestRemove,\n\t\t\t})\n\t\t: defaultRows\n\n\treturn (\n\t\t<div className={cn('space-y-2', className)}>\n\t\t\t{label && <p className='text-ui-fg text-sm font-medium'>{label}</p>}\n\n\t\t\t{filesPosition === 'above' && fileList}\n\n\t\t\t<Dropzone\n\t\t\t\taccept={uploader.accept}\n\t\t\t\tmultiple={options.multiple}\n\t\t\t\tdisabled={disabled || uploader.isUploading}\n\t\t\t\tcapture={capture}\n\t\t\t\tsize={size}\n\t\t\t\tshortcut={shortcut}\n\t\t\t\tonFiles={incoming => void uploader.addFiles(incoming)}\n\t\t\t>\n\t\t\t\t{icon !== null && (\n\t\t\t\t\t<span className='text-ui-placeholder group-hover/dz:text-ui-primary group-data-dragging/dz:text-ui-primary mb-1.5 inline-flex justify-center transition-all duration-200 group-hover/dz:-translate-y-0.5 group-data-dragging/dz:-translate-y-1 group-data-dragging/dz:scale-110'>\n\t\t\t\t\t\t{icon ?? (\n\t\t\t\t\t\t\t<UploadCloudIcon\n\t\t\t\t\t\t\t\tclassName={size === 'sm' ? 'h-5 w-5' : 'h-7 w-7'}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</span>\n\t\t\t\t)}\n\t\t\t\t<p className='text-ui-muted group-hover/dz:text-ui-fg text-sm font-medium transition-colors duration-200'>\n\t\t\t\t\t{coarse ? copy.tapPrompt : copy.dropPrompt}\n\t\t\t\t</p>\n\t\t\t\t<p className='text-ui-placeholder mt-1 text-xs'>\n\t\t\t\t\t{description ?? uploader.accept.replaceAll(',', ' · ')}\n\t\t\t\t</p>\n\t\t\t</Dropzone>\n\n\t\t\t{filesPosition === 'below' && fileList}\n\n\t\t\t{manual && uploader.hasPending && (\n\t\t\t\t<button\n\t\t\t\t\ttype='button'\n\t\t\t\t\tonClick={() => void uploader.upload()}\n\t\t\t\t\tdisabled={disabled || uploader.isUploading}\n\t\t\t\t\tclassName='bg-ui-primary text-ui-primary-fg hover:bg-ui-primary-hover focus-visible:ring-ui-ring rounded-ui h-10 w-full cursor-pointer px-4 text-sm font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50'\n\t\t\t\t>\n\t\t\t\t\t{copy.uploadAll}\n\t\t\t\t</button>\n\t\t\t)}\n\n\t\t\t<FileViewer {...viewer.viewerProps} labels={options.labels} />\n\n\t\t\t<ConfirmDialog\n\t\t\t\topen={removing !== null}\n\t\t\t\ttitle={confirmCopy.title ?? copy.confirmRemoveTitle}\n\t\t\t\tmessage={\n\t\t\t\t\tconfirmCopy.message ??\n\t\t\t\t\tcopy.confirmRemoveMessage(removing?.fileName ?? '')\n\t\t\t\t}\n\t\t\t\tonConfirm={() => {\n\t\t\t\t\tif (removing) forgetStored(removing)\n\t\t\t\t\tsetRemoving(null)\n\t\t\t\t}}\n\t\t\t\tonCancel={() => setRemoving(null)}\n\t\t\t\tlabels={options.labels}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n"]}