img-upload-kit 0.0.0-stage → 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.
- package/CHANGELOG.md +89 -0
- package/LICENSE +21 -0
- package/MIGRATION.md +192 -0
- package/README.md +242 -2
- package/dist/bin.js +1186 -0
- package/dist/bin.js.map +1 -0
- package/dist/blur.cjs +41 -0
- package/dist/blur.cjs.map +1 -0
- package/dist/blur.d.cts +17 -0
- package/dist/blur.d.ts +17 -0
- package/dist/blur.js +41 -0
- package/dist/blur.js.map +1 -0
- package/dist/blurDataUtils-DveBRtqE.d.cts +43 -0
- package/dist/blurDataUtils-yx9Q6HlU.d.ts +43 -0
- package/dist/blurService-D5TpMNji.d.ts +83 -0
- package/dist/blurService-DacwylJx.d.cts +83 -0
- package/dist/chunk-2OVNXHTN.cjs +514 -0
- package/dist/chunk-2OVNXHTN.cjs.map +1 -0
- package/dist/chunk-3ICG2SLL.cjs +135 -0
- package/dist/chunk-3ICG2SLL.cjs.map +1 -0
- package/dist/chunk-4ASFG3KB.js +514 -0
- package/dist/chunk-4ASFG3KB.js.map +1 -0
- package/dist/chunk-AI3JJLSA.js +2370 -0
- package/dist/chunk-AI3JJLSA.js.map +1 -0
- package/dist/chunk-CV23O4YU.js +145 -0
- package/dist/chunk-CV23O4YU.js.map +1 -0
- package/dist/chunk-G7LLSKBV.js +158 -0
- package/dist/chunk-G7LLSKBV.js.map +1 -0
- package/dist/chunk-IB3TEDLR.js +294 -0
- package/dist/chunk-IB3TEDLR.js.map +1 -0
- package/dist/chunk-KJVYWKIG.cjs +158 -0
- package/dist/chunk-KJVYWKIG.cjs.map +1 -0
- package/dist/chunk-NEDBIIE3.cjs +226 -0
- package/dist/chunk-NEDBIIE3.cjs.map +1 -0
- package/dist/chunk-QHU7FUO4.cjs +37 -0
- package/dist/chunk-QHU7FUO4.cjs.map +1 -0
- package/dist/chunk-QQHZJKNA.js +135 -0
- package/dist/chunk-QQHZJKNA.js.map +1 -0
- package/dist/chunk-S2IFAWJK.js +37 -0
- package/dist/chunk-S2IFAWJK.js.map +1 -0
- package/dist/chunk-TT5C7K3Q.js +226 -0
- package/dist/chunk-TT5C7K3Q.js.map +1 -0
- package/dist/chunk-U2TWTEBY.cjs +2370 -0
- package/dist/chunk-U2TWTEBY.cjs.map +1 -0
- package/dist/chunk-WISG74VL.cjs +294 -0
- package/dist/chunk-WISG74VL.cjs.map +1 -0
- package/dist/chunk-YRXXQUDE.cjs +145 -0
- package/dist/chunk-YRXXQUDE.cjs.map +1 -0
- package/dist/cli.cjs +1241 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +99 -0
- package/dist/cli.d.ts +99 -0
- package/dist/cli.js +1194 -0
- package/dist/cli.js.map +1 -0
- package/dist/headless.cjs +27 -0
- package/dist/headless.cjs.map +1 -0
- package/dist/headless.d.cts +4 -0
- package/dist/headless.d.ts +4 -0
- package/dist/headless.js +27 -0
- package/dist/headless.js.map +1 -0
- package/dist/index-BIdnqtW8.d.ts +234 -0
- package/dist/index-Brk_uHs6.d.cts +234 -0
- package/dist/index-CPMlaQsC.d.ts +635 -0
- package/dist/index-DHINe-rA.d.cts +635 -0
- package/dist/index.cjs +65 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +43 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +65 -0
- package/dist/index.js.map +1 -0
- package/dist/memoryAdapter-Ck0ccZbF.d.cts +25 -0
- package/dist/memoryAdapter-DxEKaG0b.d.ts +25 -0
- package/dist/placeholders-C4ftwaII.d.ts +5 -0
- package/dist/placeholders-x_3rt65M.d.cts +5 -0
- package/dist/react.cjs +3779 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +476 -0
- package/dist/react.d.ts +476 -0
- package/dist/react.js +3779 -0
- package/dist/react.js.map +1 -0
- package/dist/server-handler.cjs +14 -0
- package/dist/server-handler.cjs.map +1 -0
- package/dist/server-handler.d.cts +3 -0
- package/dist/server-handler.d.ts +3 -0
- package/dist/server-handler.js +14 -0
- package/dist/server-handler.js.map +1 -0
- package/dist/server.cjs +1801 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +142 -0
- package/dist/server.d.ts +142 -0
- package/dist/server.js +1801 -0
- package/dist/server.js.map +1 -0
- package/dist/storage.cjs +447 -0
- package/dist/storage.cjs.map +1 -0
- package/dist/storage.d.cts +163 -0
- package/dist/storage.d.ts +163 -0
- package/dist/storage.js +447 -0
- package/dist/storage.js.map +1 -0
- package/dist/styles/animated-image.css +112 -0
- package/dist/styles/dropzone-and-tiles.css +247 -0
- package/dist/styles/modals-and-dock.css +248 -0
- package/dist/styles/primitives.css +197 -0
- package/dist/styles/quality-and-inputs.css +184 -0
- package/dist/styles/tokens.css +123 -0
- package/dist/styles.css +1122 -0
- package/dist/types-BrP-o9nd.d.cts +85 -0
- package/dist/types-sZ3KoFQY.d.ts +85 -0
- package/dist/types-yShGNQnW.d.cts +61 -0
- package/dist/types-yShGNQnW.d.ts +61 -0
- package/dist/upload-C5Trd6Dh.d.cts +154 -0
- package/dist/upload-C5Trd6Dh.d.ts +154 -0
- package/package.json +198 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/image-upload-kit/image-upload-kit/dist/react.cjs","../src/react/hooks/index.ts","../src/react/hooks/useBlurService.ts","../src/react/hooks/useDialog.ts","../src/react/icons.tsx","../src/react/components/AltTextInput.tsx","../src/react/components/AltTextModal.tsx","../src/react/components/BlurImage.tsx","../src/react/components/AnimatedImage/AnimatedImage.tsx","../src/react/components/AnimatedImage/placeholder.ts","../src/react/components/AnimatedImage/useImageReveal.ts","../src/react/components/BlurServiceDebugger.tsx","../src/react/components/BlurVisualizationModal.tsx","../src/react/utils/canvasSampler.ts","../src/react/components/BlurColorControls.tsx","../src/react/components/SaveButton.tsx","../src/react/components/ImageUpload.tsx","../src/react/components/MultiImageUpload.tsx","../src/react/components/MultiDropzoneViews.tsx","../src/react/components/MultiUploadHeaderAlerts.tsx","../src/react/components/PreviewTile.tsx","../src/react/components/QualitySelector.tsx","../src/react/components/UploadProgressPanel.tsx","../src/react/components/SingleImageUpload.tsx","../src/react/components/SingleDropzoneContent.tsx"],"names":["useEffect","jsxs","jsx","useState","useMemo","useRef","useId","createPortal","forwardRef","Fragment","p","useImperativeHandle"],"mappings":"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oBAAA;AAEVA,oBAAAA;AAAiB,kBAAA;AACnB,gBAAA;AACAA,gCAAAA;AAAC,kBAAA;AAAA,kBAAA;AACM,oBAAA;AACU,oBAAA;AACN,oBAAA;AACM,oBAAA;AAEfA,oBAAAA;AAAa,kBAAA;AACf,gBAAA;AACF,cAAA;AAEFD,8BAAAA;AAAC,gBAAA;AAAA,gBAAA;AACgB,kBAAA;AACG,kBAAA;AAEjB,kBAAA;AACCC,oBAAAA;AAMD,oBAAA;AAAA,kBAAA;AAAA,gBAAA;AACH,cAAA;AAAA,YAAA;AAAA,UAAA;AACF,QAAA;AAAA,MAAA;AACF,IAAA;AAGsB,IAAA;AAGA,sBAAA;AAChB,MAAA;AAGG,IAAA;AAEX,EAAA;AAEJ;AAEsD;AAMpB;AhB+6Ge;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/image-upload-kit/image-upload-kit/dist/react.cjs","sourcesContent":[null,"import { useEffect } from 'react';\nimport {\n blurService,\n type BlurSize,\n useProgressiveBlur,\n} from './useBlurService';\n\nexport * from './useBlurService';\nexport {\n extractClipboardImageFiles,\n type PasteTargetMode,\n toFileListLike,\n useClipboardPaste,\n type UseClipboardPasteOptions,\n} from './useClipboardPaste';\nexport { useDialog, type UseDialogOptions } from './useDialog';\nexport {\n useDragAndDrop,\n type UseDragAndDropOptions,\n} from './useDragAndDrop';\nexport { useFilePreview, type UseFilePreviewOptions } from './useFilePreview';\nexport {\n type UploadCallOptions,\n useImageUpload,\n type UseImageUploadOptions,\n} from './useImageUpload';\nexport {\n buildUploadFormData,\n createUploadAbortError,\n isUploadAbortError,\n parseErrorPayload,\n type UploadFormFields,\n uploadViaXhr,\n type XhrUploadOptions,\n} from './xhrUpload';\n\nexport const useProgressiveImage = useProgressiveBlur;\n\nexport function useBlurPreload(\n imageSrcs: string[],\n size: BlurSize = 'small',\n): void {\n useEffect(() => {\n if (imageSrcs.length > 0) {\n blurService.preloadBlurData(imageSrcs, size);\n }\n }, [imageSrcs, size]);\n}\n","import { useMemo } from 'react';\nimport { blurService } from '../../blur/blurService';\nimport { DEFAULT_PLACEHOLDERS } from '../../blur/placeholders';\nimport type { BlurPlaceholderType, BlurSize } from '../../blur/types';\n\nexport function useBlurDataURL(\n imageSrc: string | undefined,\n options: {\n type?: BlurPlaceholderType;\n size?: BlurSize;\n } = {},\n): string {\n const { type = 'default', size = 'small' } = options;\n\n return useMemo(() => {\n if (!imageSrc) return DEFAULT_PLACEHOLDERS[type];\n return blurService.getBlurDataURL(imageSrc, { type, size });\n }, [imageSrc, type, size]);\n}\n\nexport function useBulkBlurData(\n imageSrcs: string[],\n options: {\n type?: BlurPlaceholderType;\n size?: BlurSize;\n } = {},\n): Record<string, string> {\n const { type = 'default', size = 'small' } = options;\n\n return useMemo(() => {\n return blurService.getBulkBlurData(imageSrcs, { type, size });\n }, [imageSrcs, type, size]);\n}\n\nexport function useProgressiveBlur(\n imageSrc: string | undefined,\n size: BlurSize = 'small',\n) {\n return useMemo(() => {\n if (!imageSrc) {\n return {\n color: '#E5E7EB',\n blur: DEFAULT_PLACEHOLDERS.default,\n hasBlur: false,\n };\n }\n return blurService.getProgressiveData(imageSrc, size);\n }, [imageSrc, size]);\n}\n\nexport function useHasBlurHash(imageSrc: string | undefined): boolean {\n return useMemo(() => {\n if (!imageSrc) return false;\n return blurService.hasBlurHash(imageSrc);\n }, [imageSrc]);\n}\n\nexport function useDominantColor(imageSrc: string | undefined): string {\n return useMemo(() => {\n if (!imageSrc) return '#E5E7EB';\n return blurService.getDominantColor(imageSrc);\n }, [imageSrc]);\n}\n\nexport function useBlurMetadata() {\n return useMemo(() => {\n return blurService.getMetadata();\n }, []);\n}\n\nexport function useBlurHash(imageSrc: string | undefined): string | null {\n return useMemo(() => {\n if (!imageSrc) return null;\n return blurService.getBlurHash(imageSrc);\n }, [imageSrc]);\n}\n\nexport function useBlurDataWithColor(\n imageSrc: string | undefined,\n size: BlurSize = 'small',\n): {\n blurDataUrl: string;\n blurColor: string;\n hasBlur: boolean;\n} {\n return useMemo(() => {\n if (!imageSrc) {\n return {\n blurDataUrl: DEFAULT_PLACEHOLDERS.default,\n blurColor: '#E5E7EB',\n hasBlur: false,\n };\n }\n const progressive = blurService.getProgressiveData(imageSrc, size);\n return {\n blurDataUrl: progressive.blur,\n blurColor: progressive.color,\n hasBlur: progressive.hasBlur,\n };\n }, [imageSrc, size]);\n}\n\nexport function useBlurVariant(\n imageSrc: string | undefined,\n size: BlurSize = 'small',\n type: BlurPlaceholderType = 'default',\n): string {\n return useMemo(() => {\n if (!imageSrc) return DEFAULT_PLACEHOLDERS[type];\n return blurService.getBlurDataURL(imageSrc, { type, size });\n }, [imageSrc, size, type]);\n}\n\nexport { blurService, DEFAULT_PLACEHOLDERS };\nexport type { BlurPlaceholderType, BlurSize };\n","import { type RefObject, useEffect, useId, useRef } from 'react';\n\nconst FOCUSABLE_SELECTOR = [\n 'button:not(:disabled)',\n '[href]',\n 'input:not(:disabled):not([type=\"hidden\"])',\n 'select:not(:disabled)',\n 'textarea:not(:disabled)',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(', ');\n\nexport interface UseDialogOptions {\n isOpen: boolean;\n onClose?: () => void;\n initialFocusRef?: RefObject<HTMLElement | null>;\n lockScroll?: boolean;\n}\n\nexport function useDialog({\n isOpen,\n onClose,\n initialFocusRef,\n lockScroll = true,\n}: UseDialogOptions) {\n const dialogRef = useRef<HTMLDivElement | null>(null);\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n const titleId = useId();\n const descriptionId = useId();\n\n useEffect(() => {\n if (!isOpen || typeof document === 'undefined') return;\n\n const previouslyFocused =\n document.activeElement instanceof HTMLElement\n ? document.activeElement\n : null;\n\n const prevOverflow = document.body.style.overflow;\n if (lockScroll) {\n document.body.style.overflow = 'hidden';\n }\n\n const focusInitial = () => {\n const container = dialogRef.current;\n if (!container) return;\n if (initialFocusRef?.current) {\n initialFocusRef.current.focus();\n return;\n }\n if (\n document.activeElement &&\n container.contains(document.activeElement)\n ) {\n return;\n }\n const focusables = Array.from(\n container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR),\n );\n if (focusables.length > 0) {\n focusables[0].focus();\n } else {\n container.focus();\n }\n };\n\n focusInitial();\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape' && onCloseRef.current) {\n event.stopPropagation();\n onCloseRef.current();\n return;\n }\n\n if (event.key !== 'Tab') return;\n const container = dialogRef.current;\n if (!container) return;\n\n const focusables = Array.from(\n container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR),\n );\n if (focusables.length === 0) {\n event.preventDefault();\n return;\n }\n\n const first = focusables[0];\n const last = focusables[focusables.length - 1];\n const active = document.activeElement as HTMLElement | null;\n\n if (event.shiftKey) {\n if (!active || active === first || !container.contains(active)) {\n event.preventDefault();\n last.focus();\n }\n } else if (!active || active === last || !container.contains(active)) {\n event.preventDefault();\n first.focus();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n if (lockScroll) {\n document.body.style.overflow = prevOverflow;\n }\n if (previouslyFocused && typeof previouslyFocused.focus === 'function') {\n try {\n previouslyFocused.focus();\n } catch {\n // Ignore focus restore errors if node was detached\n }\n }\n };\n }, [isOpen, lockScroll, initialFocusRef]);\n\n return {\n dialogRef,\n titleId,\n descriptionId,\n };\n}\n","/**\n * Inline SVG icon set (24×24, stroke-based) used by the styled components.\n *\n * Replaces the former `lucide-react` dependency so consumers do not need to\n * install an icon library. Path data is derived from Lucide (ISC license,\n * https://lucide.dev/license). The prop API mirrors the subset of Lucide's\n * API the kit relied on: `size`, `strokeWidth`, `color`, `className` and any\n * other SVG attribute. Icons are decorative (`aria-hidden`) by default unless\n * an `aria-label` / `aria-labelledby` is supplied.\n */\nimport type { JSX, SVGProps } from 'react';\n\ntype IconTag = 'path' | 'circle';\ntype IconNode = ReadonlyArray<readonly [IconTag, Readonly<Record<string, string>>]>;\n\nexport interface IconProps extends Omit<SVGProps<SVGSVGElement>, 'ref'> {\n /** Width & height in px (number) or any CSS length (string). Default 24. */\n size?: number | string;\n /** Stroke width. Default 2. */\n strokeWidth?: number | string;\n /** Stroke color. Default `currentColor`. */\n color?: string;\n}\n\nexport type IconComponent = ((props: IconProps) => JSX.Element) & {\n displayName?: string;\n};\n\nfunction createIcon(name: string, nodes: IconNode): IconComponent {\n const Icon = ({\n size = 24,\n strokeWidth = 2,\n color = 'currentColor',\n className,\n children,\n ...rest\n }: IconProps) => {\n const labelled =\n rest['aria-label'] !== undefined || rest['aria-labelledby'] !== undefined;\n const baseClass = `iuk-icon iuk-icon--${name}`;\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke={color}\n strokeWidth={strokeWidth}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className ? `${baseClass} ${className}` : baseClass}\n aria-hidden={labelled ? undefined : true}\n focusable=\"false\"\n {...rest}\n >\n {nodes.map(([Tag, attrs], index) => (\n <Tag key={index} {...attrs} />\n ))}\n {children}\n </svg>\n );\n };\n Icon.displayName = `Icon(${name})`;\n return Icon;\n}\n\nconst p = (d: string) => ['path', { d }] as const;\nconst c = (cx: string, cy: string, r: string, fill?: string) => {\n const attrs: Record<string, string> = { cx, cy, r };\n if (fill) attrs.fill = fill;\n return ['circle', attrs] as const;\n};\n\nconst UPLOAD_TRAY = 'M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4';\n\nexport const UploadIcon = createIcon('upload', [\n p('M12 3v12'),\n p('m17 8-5-5-5 5'),\n p(UPLOAD_TRAY),\n]);\n\nexport const DownloadIcon = createIcon('download', [\n p('M12 15V3'),\n p(UPLOAD_TRAY),\n p('m7 10 5 5 5-5'),\n]);\n\nexport const ImagePlusIcon = createIcon('image-plus', [\n p('M16 5h6'),\n p('M19 2v6'),\n p('M21 11.5V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7.5'),\n p('m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21'),\n c('9', '9', '2'),\n]);\n\nexport const XIcon = createIcon('x', [p('M18 6 6 18'), p('m6 6 12 12')]);\n\nexport const CheckIcon = createIcon('check', [p('M20 6 9 17l-5-5')]);\n\nexport const MinusIcon = createIcon('minus', [p('M5 12h14')]);\n\nexport const LoaderIcon = createIcon('loader', [\n p('M21 12a9 9 0 1 1-6.219-8.56'),\n]);\n\nexport const ChevronUpIcon = createIcon('chevron-up', [p('m18 15-6-6-6 6')]);\n\nexport const ChevronDownIcon = createIcon('chevron-down', [p('m6 9 6 6 6-6')]);\n\nexport const AlertTriangleIcon = createIcon('alert-triangle', [\n p('m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3'),\n p('M12 9v4'),\n p('M12 17h.01'),\n]);\n\nexport const SaveIcon = createIcon('save', [\n p(\n 'M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z',\n ),\n p('M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7'),\n p('M7 3v4a1 1 0 0 0 1 1h7'),\n]);\n\nexport const EyeIcon = createIcon('eye', [\n p(\n 'M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0',\n ),\n c('12', '12', '3'),\n]);\n\nexport const InfoIcon = createIcon('info', [\n c('12', '12', '10'),\n p('M12 16v-4'),\n p('M12 8h.01'),\n]);\n\nexport const ZapIcon = createIcon('zap', [\n p(\n 'M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z',\n ),\n]);\n\nexport const CheckCircleIcon = createIcon('check-circle', [\n c('12', '12', '10'),\n p('m9 12 2 2 4-4'),\n]);\n\nexport const XCircleIcon = createIcon('x-circle', [\n c('12', '12', '10'),\n p('m15 9-6 6'),\n p('m9 9 6 6'),\n]);\n\nexport const TypeIcon = createIcon('type', [\n p('M12 4v16'),\n p('M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2'),\n p('M9 20h6'),\n]);\n\nexport const FolderOpenIcon = createIcon('folder-open', [\n p(\n 'm6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2',\n ),\n]);\n\nexport const PenToolIcon = createIcon('pen-tool', [\n p(\n 'M15.707 21.293a1 1 0 0 1-1.414 0l-1.586-1.586a1 1 0 0 1 0-1.414l5.586-5.586a1 1 0 0 1 1.414 0l1.586 1.586a1 1 0 0 1 0 1.414z',\n ),\n p(\n 'm18 13-1.375-6.874a1 1 0 0 0-.746-.776L3.235 2.028a1 1 0 0 0-1.207 1.207L5.35 15.879a1 1 0 0 0 .776.746L13 18',\n ),\n p('m2.3 2.3 7.286 7.286'),\n c('11', '11', '2'),\n]);\n\nexport const WandIcon = createIcon('wand', [\n p(\n 'm21.64 3.64-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.2 1.2 0 0 0 1.72 0L21.64 5.36a1.2 1.2 0 0 0 0-1.72',\n ),\n p('m14 7 3 3'),\n p('M5 6v4'),\n p('M19 14v4'),\n p('M10 2v2'),\n p('M7 8H3'),\n p('M21 16h-4'),\n p('M11 3H9'),\n]);\n\nexport const TrashIcon = createIcon('trash', [\n p('M10 11v6'),\n p('M14 11v6'),\n p('M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6'),\n p('M3 6h18'),\n p('M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2'),\n]);\n\nexport const PaletteIcon = createIcon('palette', [\n p(\n 'M12 22a1 1 0 0 1 0-20 10 9 0 0 1 10 9 5 5 0 0 1-5 5h-2.25a1.75 1.75 0 0 0-1.4 2.8l.3.4a1.75 1.75 0 0 1-1.4 2.8z',\n ),\n c('13.5', '6.5', '.5', 'currentColor'),\n c('17.5', '10.5', '.5', 'currentColor'),\n c('6.5', '12.5', '.5', 'currentColor'),\n c('8.5', '7.5', '.5', 'currentColor'),\n]);\n","import { TypeIcon } from '../icons';\nimport { useId } from 'react';\nimport type { UploadLocale } from '../../types';\nimport { useImageUploadContext } from '../context';\nimport {\n normalizeUploadLocale,\n resolveTranslations,\n type UploadTranslations,\n} from '../i18n';\nimport { resolveSlotClass } from '../utils/slotStyles';\n\nexport interface AltTextInputProps {\n value: string;\n onChange: (value: string) => void;\n disabled?: boolean;\n placeholder?: string;\n maxLength?: number;\n label?: string;\n showHint?: boolean;\n locale?: UploadLocale;\n translations?: Partial<UploadTranslations>;\n unstyled?: boolean;\n}\n\nexport function AltTextInput({\n value,\n onChange,\n disabled = false,\n placeholder,\n maxLength = 200,\n label,\n showHint = true,\n locale: propLocale,\n translations,\n unstyled: propUnstyled,\n}: AltTextInputProps) {\n const ctx = useImageUploadContext();\n const isUnstyled = propUnstyled ?? ctx.unstyled;\n const locale = normalizeUploadLocale(propLocale || ctx.locale);\n const ui = resolveTranslations(locale, translations || ctx.translations);\n const resolvedPlaceholder = placeholder || ui.describeImagePlaceholder;\n const resolvedLabel = label || ui.addImageDescription;\n const inputId = useId();\n const hintId = showHint ? `${inputId}-hint` : undefined;\n const cls = (defaultClass: string) => resolveSlotClass(defaultClass, isUnstyled);\n\n return (\n <div\n data-slot=\"alt-input\"\n data-unstyled={isUnstyled || undefined}\n className={cls('iuk-alt-input')}\n dir={locale === 'ar' ? 'rtl' : 'ltr'}\n >\n <div className={cls('iuk-alt-input__header')}>\n <TypeIcon size={16} />\n <label htmlFor={inputId} className={cls('iuk-alt-input__label')}>\n {resolvedLabel}\n </label>\n </div>\n <input\n id={inputId}\n type=\"text\"\n value={value}\n onChange={(e) => onChange(e.target.value)}\n placeholder={resolvedPlaceholder}\n className={cls('iuk-alt-input__field')}\n disabled={disabled}\n maxLength={maxLength}\n aria-describedby={hintId}\n />\n {showHint && (\n <p className={cls('iuk-alt-input__hint')} id={hintId}>\n <span>\n {value.length}/{maxLength} {ui.characters}\n </span>\n <span>{ui.usedForA11ySeo}</span>\n </p>\n )}\n </div>\n );\n}\n\nexport default AltTextInput;\n","import { CheckCircleIcon as CheckCircle2, TypeIcon, XIcon as X } from '../icons';\nimport { useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport type { UploadLocale } from '../../types';\nimport { useImageUploadContext } from '../context';\nimport { useDialog } from '../hooks/useDialog';\nimport {\n normalizeUploadLocale,\n resolveTranslations,\n type UploadTranslations,\n} from '../i18n';\nimport type { CustomImageRenderer } from '../types';\nimport { resolveSlotClass } from '../utils/slotStyles';\nimport { BlurImage } from './BlurImage';\n\nexport interface AltTextModalProps {\n imageUrl: string;\n initialAltText?: string;\n onSave: (altText: string) => void;\n onClose: () => void;\n locale?: UploadLocale;\n translations?: Partial<UploadTranslations>;\n renderImage?: CustomImageRenderer;\n unstyled?: boolean;\n}\n\nexport function AltTextModal({\n imageUrl,\n initialAltText = '',\n onSave,\n onClose,\n locale: propLocale,\n translations,\n renderImage,\n unstyled: propUnstyled,\n}: AltTextModalProps) {\n const ctx = useImageUploadContext();\n const isUnstyled = propUnstyled ?? ctx.unstyled;\n const locale = normalizeUploadLocale(propLocale || ctx.locale);\n const ui = resolveTranslations(locale, translations || ctx.translations);\n const [localAltText, setLocalAltText] = useState(initialAltText);\n const inputRef = useRef<HTMLInputElement | null>(null);\n const { dialogRef, titleId, descriptionId } = useDialog({\n isOpen: true,\n onClose,\n initialFocusRef: inputRef,\n });\n const cls = (defaultClass: string) => resolveSlotClass(defaultClass, isUnstyled);\n\n const handleSave = () => {\n onSave(localAltText);\n onClose();\n };\n\n const content = (\n <div\n data-slot=\"alt-modal-backdrop\"\n data-unstyled={isUnstyled || undefined}\n className={cls('iuk-modal-backdrop')}\n dir={locale === 'ar' ? 'rtl' : 'ltr'}\n onClick={onClose}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n aria-describedby={descriptionId}\n >\n <div\n ref={dialogRef}\n data-slot=\"alt-modal\"\n className={cls('iuk-alt-modal')}\n onClick={(e) => e.stopPropagation()}\n >\n <div className={cls('iuk-alt-modal__header')}>\n <div className={cls('iuk-alt-modal__title')}>\n <TypeIcon size={18} />\n <span id={titleId}>{ui.addImageDescription}</span>\n </div>\n <button\n type=\"button\"\n className={cls('iuk-icon-btn')}\n onClick={onClose}\n title={ui.close}\n aria-label={ui.close}\n >\n <X size={18} />\n </button>\n </div>\n\n <div className={cls('iuk-alt-modal__preview')}>\n <BlurImage\n src={imageUrl}\n alt={ui.previewAlt}\n objectFit=\"contain\"\n renderImage={renderImage}\n />\n </div>\n\n <input\n ref={inputRef}\n type=\"text\"\n className={cls('iuk-alt-input__field')}\n value={localAltText}\n onChange={(e) => setLocalAltText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n handleSave();\n }\n }}\n placeholder={ui.describeImagePlaceholder}\n maxLength={200}\n aria-labelledby={titleId}\n aria-describedby={descriptionId}\n />\n\n <div id={descriptionId} className={cls('iuk-alt-input__hint')}>\n <span>\n {localAltText.length}/200 {ui.characters}\n </span>\n <span>{ui.usedForA11ySeo}</span>\n </div>\n\n <div className={cls('iuk-alt-modal__actions')}>\n <button\n type=\"button\"\n className={cls('iuk-btn iuk-btn--secondary')}\n onClick={onClose}\n >\n {ui.cancel}\n </button>\n <button\n type=\"button\"\n className={cls('iuk-btn iuk-btn--primary')}\n onClick={handleSave}\n >\n <CheckCircle2 size={16} />\n <span>{ui.saveDescription}</span>\n </button>\n </div>\n </div>\n </div>\n );\n\n if (typeof document !== 'undefined') {\n return createPortal(content, document.body);\n }\n return content;\n}\n\nexport default AltTextModal;\n","import {\n type CSSProperties,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { decodeBlurHashToDataURL } from '../../blur/blurDataUtils';\nimport { useImageUploadContext } from '../context';\nimport type { CustomImageRenderer } from '../types';\n\nexport interface BlurImageProps {\n src: string;\n alt: string;\n blurDataUrl?: string | null;\n blurColor?: string | null;\n blurHash?: string | null;\n objectFit?: CSSProperties['objectFit'];\n className?: string;\n imageClassName?: string;\n style?: CSSProperties;\n renderImage?: CustomImageRenderer;\n onImageLoad?: (img: HTMLImageElement | null) => void;\n}\n\nexport function BlurImage({\n src,\n alt,\n blurDataUrl,\n blurColor,\n blurHash,\n objectFit = 'cover',\n className = '',\n imageClassName = '',\n style,\n renderImage: propRenderImage,\n onImageLoad,\n}: BlurImageProps) {\n const ctx = useImageUploadContext();\n const renderImage = propRenderImage || ctx.renderImage;\n const [loadedSrc, setLoadedSrc] = useState<string | null>(null);\n const [failedSrc, setFailedSrc] = useState<string | null>(null);\n const imgRef = useRef<HTMLImageElement | null>(null);\n const onImageLoadRef = useRef(onImageLoad);\n onImageLoadRef.current = onImageLoad;\n\n const decodedHashUrl = useMemo(() => {\n if (blurDataUrl || !blurHash) return null;\n return decodeBlurHashToDataURL(blurHash, 32, 32);\n }, [blurDataUrl, blurHash]);\n\n const effectiveBlurUrl = blurDataUrl || decodedHashUrl || undefined;\n const isLoaded = loadedSrc === src;\n const hasFailed = failedSrc === src;\n\n useEffect(() => {\n const el = imgRef.current;\n if (el && el.complete && el.naturalWidth > 0) {\n setLoadedSrc(src);\n onImageLoadRef.current?.(el);\n }\n }, [src]);\n\n const imgStyle: CSSProperties = {\n width: '100%',\n height: '100%',\n objectFit,\n opacity: isLoaded || hasFailed || !effectiveBlurUrl ? 1 : 0,\n transition: 'opacity 0.28s ease-out',\n };\n\n const escapedBlurUrl = effectiveBlurUrl ? effectiveBlurUrl.replace(/\"/g, '\\\\\"') : undefined;\n\n return (\n <div\n className={`iuk-blur-image-wrap ${className}`.trim()}\n style={{\n backgroundColor: blurColor || 'var(--iuk-placeholder-bg, #f3f4f6)',\n ...style,\n }}\n >\n {escapedBlurUrl && (\n <div\n aria-hidden=\"true\"\n className={`iuk-blur-image-backdrop ${isLoaded ? 'iuk-blur-image-backdrop--hidden' : ''}`}\n style={{\n backgroundImage: `url(\"${escapedBlurUrl}\")`,\n backgroundSize: objectFit === 'contain' ? 'contain' : 'cover',\n }}\n />\n )}\n\n {renderImage ? (\n renderImage({\n src,\n alt,\n className: `iuk-blur-image-el ${imageClassName}`.trim(),\n style: imgStyle,\n onLoad: (el) => {\n setLoadedSrc(src);\n onImageLoadRef.current?.(el);\n },\n })\n ) : (\n <img\n ref={imgRef}\n src={src}\n alt={alt}\n loading=\"lazy\"\n decoding=\"async\"\n className={`iuk-blur-image-el ${imageClassName}`.trim()}\n style={imgStyle}\n onLoad={(e) => {\n setLoadedSrc(src);\n onImageLoadRef.current?.(e.currentTarget);\n }}\n onError={() => {\n setFailedSrc(src);\n }}\n />\n )}\n </div>\n );\n}\n\nexport default BlurImage;\n","import { type CSSProperties, type SyntheticEvent, useMemo } from 'react';\nimport { cx } from '../../utils/slotStyles';\nimport {\n DEFAULT_NEUTRAL_COLORS,\n resolveBackgroundColor,\n resolveIntrinsicPlaceholderUrl,\n resolvePlaceholderUrl,\n} from './placeholder';\nimport type { AnimatedImageObjectFit, AnimatedImageProps } from './types';\nimport { useImageReveal } from './useImageReveal';\n\nconst preventDrag = (event: SyntheticEvent) => event.preventDefault();\nconst cn = (...classes: Parameters<typeof cx>) => cx(...classes) || undefined;\n\n/**\n * Blur-up image with a smooth, GPU-friendly crossfade and subtle zoom reveal.\n * Matches the Imagine-Global reference design while remaining pure React,\n * SSR-safe, and framework-agnostic — plug in `next/image` via `as`.\n */\nexport function AnimatedImage({\n image,\n src: srcProp,\n alt: altProp,\n blurDataUrl: blurDataUrlProp,\n blurHash: blurHashProp,\n blurColor: blurColorProp,\n colorPlaceholder = 'flat',\n neutralColors = DEFAULT_NEUTRAL_COLORS,\n width: widthProp,\n height: heightProp,\n fill = false,\n priority,\n quality,\n objectFit = 'cover',\n objectPosition = 'center',\n showShimmer = false,\n animationDuration = 600,\n revealScale = 1.02,\n fallbackSrc,\n renderError,\n as: ImageComponent,\n imageComponentProps,\n unstyled = false,\n wrapperClassName,\n wrapperStyle,\n wrapperProps,\n placeholderClassName,\n className,\n style,\n loading: loadingProp,\n decoding = 'async',\n draggable = false,\n onLoad,\n onError,\n ...imgProps\n}: AnimatedImageProps) {\n const src = srcProp ?? image?.url ?? '';\n const alt = altProp ?? image?.altText ?? '';\n const blurDataUrl = blurDataUrlProp ?? image?.blurDataUrl;\n const blurHash = blurHashProp ?? image?.blurHash;\n const blurColor = blurColorProp ?? image?.blurColor;\n const width = widthProp ?? (!fill ? image?.width : undefined);\n const height = heightProp ?? (!fill ? image?.height : undefined);\n\n const {\n activeSrc,\n retryKey,\n isLoaded,\n showPlaceholder,\n hasError,\n imgRef,\n handleLoad,\n handleError,\n retry,\n } = useImageReveal({\n srcKey: src,\n fallbackSrc,\n animationDuration,\n onLoad,\n });\n\n const state = hasError ? 'error' : isLoaded ? 'loaded' : 'loading';\n const resolvedObjectFit =\n (style?.objectFit as AnimatedImageObjectFit | undefined) ?? objectFit;\n const isContain = resolvedObjectFit === 'contain';\n\n const placeholderUrl = useMemo(\n () =>\n colorPlaceholder === 'gradient' || isContain\n ? resolvePlaceholderUrl({ blurDataUrl, blurHash, blurColor, neutralColors })\n : resolveIntrinsicPlaceholderUrl({ blurDataUrl, blurHash }),\n [blurDataUrl, blurHash, blurColor, colorPlaceholder, isContain, neutralColors],\n );\n const cls = (name: string) => (unstyled ? undefined : name);\n const duration = Math.max(0, animationDuration);\n const placeholderFadeDuration = Math.round(duration * (5 / 6));\n\n const containerStyle: CSSProperties = {\n backgroundColor:\n resolveBackgroundColor(blurColor, neutralColors) ??\n (unstyled\n ? undefined\n : 'var(--iuk-animated-image-bg, var(--background-card, rgba(38, 45, 56, 0.4)))'),\n ...(unstyled\n ? undefined\n : {\n ['--iuk-animated-image-duration' as string]: `${duration}ms`,\n ['--iuk-ai-ph-dur' as string]: `${placeholderFadeDuration}ms`,\n ['--iuk-animated-image-reveal-scale' as string]: String(revealScale),\n }),\n ...wrapperStyle,\n };\n\n const placeholderStyle: CSSProperties = {\n objectFit: 'cover',\n transitionDuration: `${placeholderFadeDuration}ms`,\n };\n\n const imageStyle: CSSProperties = {\n objectFit: resolvedObjectFit,\n objectPosition,\n transitionDuration: `${duration}ms`,\n ...style,\n ...(hasError ? { opacity: 0, visibility: 'hidden' as const } : undefined),\n };\n\n const isCustom = Boolean(ImageComponent);\n const loadingAttr = priority\n ? isCustom\n ? undefined\n : 'eager'\n : (loadingProp ?? (isCustom ? undefined : 'lazy'));\n\n const priorityProps = isCustom\n ? {\n ...(priority !== undefined ? { priority } : {}),\n ...(quality !== undefined ? { quality } : {}),\n }\n : priority\n ? { fetchPriority: 'high' as const }\n : {};\n\n const derivedImageSrcSet =\n !isCustom && activeSrc === src\n ? (image?.srcSet ??\n (image?.variants?.length\n ? [\n ...[...image.variants]\n .sort((a, b) => a.width - b.width)\n .map((v) => `${v.url} ${v.width}w`),\n ...(image.width ? [`${src} ${image.width}w`] : []),\n ].join(', ')\n : undefined))\n : undefined;\n const resolvedSrcSet = imgProps.srcSet ?? derivedImageSrcSet;\n const resolvedSizes =\n !isCustom && resolvedSrcSet && fill && imgProps.sizes === undefined\n ? '100vw'\n : imgProps.sizes;\n\n const sharedImgProps = {\n ...priorityProps,\n ...imgProps,\n ...(resolvedSrcSet !== undefined ? { srcSet: resolvedSrcSet } : {}),\n ...(resolvedSizes !== undefined ? { sizes: resolvedSizes } : {}),\n ...(width !== undefined ? { width } : {}),\n ...(height !== undefined ? { height } : {}),\n ...(loadingAttr !== undefined ? { loading: loadingAttr } : {}),\n src: activeSrc,\n alt,\n decoding,\n draggable,\n ref: imgRef,\n className: cn(cls('iuk-animated-image__img'), className),\n style: imageStyle,\n 'data-state': state,\n onDragStart: imgProps.onDragStart ?? preventDrag,\n onLoad: (event: SyntheticEvent<HTMLImageElement>) =>\n handleLoad(event.currentTarget),\n onError: (event: SyntheticEvent<HTMLImageElement, Event>) => {\n const isTerminal = handleError();\n if (isTerminal) {\n onError?.(event);\n }\n },\n };\n\n return (\n <div\n {...wrapperProps}\n className={cn(\n cls('iuk-animated-image'),\n fill && cls('iuk-animated-image--fill'),\n isContain && cls('iuk-animated-image--contain'),\n wrapperClassName,\n wrapperProps?.className,\n )}\n style={{ ...containerStyle, ...wrapperProps?.style }}\n data-slot=\"animated-image\"\n data-state={state}\n aria-busy={state === 'loading' || undefined}\n >\n {(showPlaceholder || isContain) && placeholderUrl && (\n <img\n src={placeholderUrl}\n alt=\"\"\n aria-hidden=\"true\"\n draggable={false}\n onDragStart={preventDrag}\n data-slot=\"animated-image-placeholder\"\n className={cn(\n cls('iuk-animated-image__placeholder'),\n isLoaded && !isContain && cls('iuk-animated-image__placeholder--hidden'),\n placeholderClassName,\n )}\n style={placeholderStyle}\n />\n )}\n\n {showShimmer && !isLoaded && !hasError && (\n <div\n aria-hidden=\"true\"\n data-slot=\"animated-image-shimmer\"\n className={cn(cls('iuk-animated-image__shimmer'))}\n />\n )}\n\n {ImageComponent ? (\n <ImageComponent\n key={retryKey > 0 ? retryKey : undefined}\n {...sharedImgProps}\n {...(fill ? { fill: true } : {})}\n {...imageComponentProps}\n />\n ) : (\n <img key={retryKey > 0 ? retryKey : undefined} {...sharedImgProps} />\n )}\n\n {hasError && renderError ? renderError({ src: activeSrc, retry }) : null}\n </div>\n );\n}\n\nexport default AnimatedImage;\n","import { decodeBlurHashToDataURL } from '../../../blur/blurDataUtils';\n\n/**\n * Default neutral colors that carry no real information about the image (common\n * DB defaults or \"empty\" values). Ignored by default so placeholders never\n * flash pitch-black or stark white unless `neutralColors={[]}` is passed.\n */\nexport const DEFAULT_NEUTRAL_COLORS = [\n '#1a1a1a',\n '#121212',\n '#000000',\n '#000',\n '#e5e7eb',\n '#ffffff',\n '#fff',\n] as const;\n\nconst HEX_COLOR = /^#(?:[0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;\nconst FUNC_COLOR = /^(?:rgb|rgba|hsl|hsla|oklch|oklab)\\([\\d\\s.,%/+-]+\\)$/i;\nconst CSS_VAR_COLOR = /^var\\(--[a-zA-Z0-9_-]+(?:\\s*,\\s*[^;{}<>()]+)?\\)$/;\n\nfunction isNeutralColor(value: string, neutralColors: readonly string[]): boolean {\n if (neutralColors.length === 0) return false;\n const lower = value.toLowerCase();\n for (const item of neutralColors) {\n if (item.toLowerCase() === lower) return true;\n }\n return false;\n}\n\n/**\n * Returns a safe, meaningful literal color (`#hex`, `rgb(...)`, `hsl(...)`, `oklch(...)`)\n * suitable for inline SVG embedding, or `undefined` when empty/neutral/invalid.\n * Rejects CSS variables (`var(--*)`) because SVG data URLs cannot resolve host DOM tokens.\n */\nexport function resolveMeaningfulColor(\n color?: string | null,\n neutralColors: readonly string[] = DEFAULT_NEUTRAL_COLORS,\n): string | undefined {\n const value = color?.trim();\n if (!value) return undefined;\n if (isNeutralColor(value, neutralColors)) return undefined;\n if (!HEX_COLOR.test(value) && !FUNC_COLOR.test(value)) return undefined;\n return value;\n}\n\n/**\n * Returns a safe CSS background-color value for the wrapper element.\n * Accepts literal colors AND safe CSS custom property expressions (`var(--token)`),\n * while rejecting neutral defaults and CSS injection payloads.\n */\nexport function resolveBackgroundColor(\n color?: string | null,\n neutralColors: readonly string[] = DEFAULT_NEUTRAL_COLORS,\n): string | undefined {\n const value = color?.trim();\n if (!value) return undefined;\n if (isNeutralColor(value, neutralColors)) return undefined;\n if (HEX_COLOR.test(value) || FUNC_COLOR.test(value) || CSS_VAR_COLOR.test(value)) {\n return value;\n }\n return undefined;\n}\n\n/**\n * Inline SVG data URL that renders a soft gradient placeholder.\n * Uses the dominant color when provided, otherwise a neutral slate gradient.\n */\nexport function createFallbackBlurSvg(\n color?: string | null,\n neutralColors: readonly string[] = DEFAULT_NEUTRAL_COLORS,\n): string {\n const meaningful = resolveMeaningfulColor(color, neutralColors);\n const stop1 = meaningful ?? '#2c3340';\n const stop2 = meaningful ? '#0f172a' : '#1e242d';\n const svg =\n '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\" width=\"100%\" height=\"100%\">' +\n '<defs>' +\n '<linearGradient id=\"g\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">' +\n `<stop offset=\"0%\" stop-color=\"${stop1}\" stop-opacity=\"1\"/>` +\n `<stop offset=\"55%\" stop-color=\"${stop1}\" stop-opacity=\"0.78\"/>` +\n `<stop offset=\"100%\" stop-color=\"${stop2}\" stop-opacity=\"0.96\"/>` +\n '</linearGradient>' +\n '<radialGradient id=\"h\" cx=\"24%\" cy=\"22%\" r=\"65%\">' +\n '<stop offset=\"0%\" stop-color=\"#ffffff\" stop-opacity=\"0.22\"/>' +\n '<stop offset=\"100%\" stop-color=\"#ffffff\" stop-opacity=\"0\"/>' +\n '</radialGradient>' +\n '</defs>' +\n '<rect width=\"100%\" height=\"100%\" fill=\"url(#g)\"/>' +\n '<rect width=\"100%\" height=\"100%\" fill=\"url(#h)\"/>' +\n '</svg>';\n return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;\n}\n\nexport interface PlaceholderSources {\n blurDataUrl?: string | null;\n blurHash?: string | null;\n blurColor?: string | null;\n neutralColors?: readonly string[];\n}\n\n/**\n * Resolves an intrinsic image placeholder (`blurDataUrl` or decoded `blurHash`)\n * without falling back to an SVG gradient. Returns `undefined` when neither is present.\n */\nexport function resolveIntrinsicPlaceholderUrl({\n blurDataUrl,\n blurHash,\n}: Pick<PlaceholderSources, 'blurDataUrl' | 'blurHash'>): string | undefined {\n const dataUrl = blurDataUrl?.trim();\n if (dataUrl) return dataUrl;\n if (blurHash && typeof document !== 'undefined') {\n try {\n const decoded = decodeBlurHashToDataURL(blurHash, 32, 32);\n if (decoded) return decoded;\n } catch {\n // Invalid hash: ignore.\n }\n }\n return undefined;\n}\n\n/**\n * Resolves the best available placeholder URL in priority order:\n * 1. `blurDataUrl` (LQIP data URL / remote URL)\n * 2. `blurHash` (decoded client-side; browser only)\n * 3. Gradient SVG derived from `blurColor` (or neutral fallback)\n */\nexport function resolvePlaceholderUrl({\n blurDataUrl,\n blurHash,\n blurColor,\n neutralColors = DEFAULT_NEUTRAL_COLORS,\n}: PlaceholderSources): string {\n const intrinsic = resolveIntrinsicPlaceholderUrl({ blurDataUrl, blurHash });\n if (intrinsic) return intrinsic;\n return createFallbackBlurSvg(blurColor, neutralColors);\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport interface UseImageRevealOptions {\n /** Identity of the primary source; a change resets the reveal state. */\n srcKey: string;\n /** Optional fallback URL tried once if `srcKey` fails to load. */\n fallbackSrc?: string;\n /** Crossfade duration in ms. */\n animationDuration: number;\n onLoad?: (img: HTMLImageElement | null) => void;\n}\n\nexport interface ImageRevealState {\n /** Active image URL (`srcKey` initially, or `fallbackSrc` after primary failure). */\n activeSrc: string;\n /** Monotonic counter incremented when `retry()` is invoked. */\n retryKey: number;\n /** True once the sharp image is decoded and ready to fade in. */\n isLoaded: boolean;\n /** Whether the placeholder layer is still mounted (kept until fade completes, or on error). */\n showPlaceholder: boolean;\n /** True when the image (and optional `fallbackSrc`) failed to load. */\n hasError: boolean;\n /** Callback ref to attach to the underlying `<img>` element. */\n imgRef: (node: HTMLImageElement | null) => void;\n handleLoad: (img?: HTMLImageElement | null) => void;\n /** Returns `true` if the error is terminal, or `false` if switching to `fallbackSrc`. */\n handleError: () => boolean;\n /** Resets error state and retries loading from the primary `srcKey`. */\n retry: () => void;\n}\n\nconst PLACEHOLDER_UNMOUNT_BUFFER_MS = 50;\n\n/**\n * Framework-agnostic reveal state machine for blur-up images:\n * - resets synchronously when `srcKey` changes (no stale 1-frame flash)\n * - pre-decodes via `HTMLImageElement.decode()` before crossfading\n * - detects already-cached images after the first paint\n * - unmounts placeholder after crossfade (`animationDuration + 50ms`)\n * - on error: tries `fallbackSrc` once if provided; on terminal error keeps placeholder visible\n */\nexport function useImageReveal({\n srcKey,\n fallbackSrc,\n animationDuration,\n onLoad,\n}: UseImageRevealOptions): ImageRevealState {\n const [prevSrc, setPrevSrc] = useState(srcKey);\n const [usingFallback, setUsingFallback] = useState(false);\n const [retryKey, setRetryKey] = useState(0);\n const [isLoaded, setIsLoaded] = useState(false);\n const [showPlaceholder, setShowPlaceholder] = useState(true);\n const [hasError, setHasError] = useState(false);\n const [node, setNode] = useState<HTMLImageElement | null>(null);\n\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const mountedRef = useRef(true);\n const activeSrc = usingFallback && fallbackSrc ? fallbackSrc : srcKey;\n const activeSrcRef = useRef(activeSrc);\n const onLoadRef = useRef(onLoad);\n\n useEffect(() => {\n onLoadRef.current = onLoad;\n }, [onLoad]);\n\n const clearTimer = useCallback(() => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n }, []);\n\n if (prevSrc !== srcKey) {\n setPrevSrc(srcKey);\n setUsingFallback(false);\n setIsLoaded(false);\n setShowPlaceholder(true);\n setHasError(false);\n }\n\n useEffect(() => {\n activeSrcRef.current = activeSrc;\n clearTimer();\n }, [activeSrc, clearTimer]);\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n clearTimer();\n };\n }, [clearTimer]);\n\n const handleLoad = useCallback(\n (img?: HTMLImageElement | null) => {\n const el = img ?? node;\n const loadedFor = activeSrcRef.current;\n const reveal = () => {\n if (!mountedRef.current || loadedFor !== activeSrcRef.current) return;\n setHasError(false);\n setIsLoaded(true);\n clearTimer();\n const duration = Math.max(0, animationDuration);\n timeoutRef.current = setTimeout(() => {\n if (mountedRef.current) setShowPlaceholder(false);\n timeoutRef.current = null;\n }, duration + PLACEHOLDER_UNMOUNT_BUFFER_MS);\n onLoadRef.current?.(el ?? null);\n };\n if (el && typeof el.decode === 'function') {\n el.decode().then(reveal, reveal);\n } else {\n reveal();\n }\n },\n [animationDuration, clearTimer, node],\n );\n\n const handleError = useCallback((): boolean => {\n if (!mountedRef.current) return false;\n clearTimer();\n if (fallbackSrc && !usingFallback && fallbackSrc !== srcKey) {\n setUsingFallback(true);\n setIsLoaded(false);\n setShowPlaceholder(true);\n setHasError(false);\n return false;\n }\n setHasError(true);\n setIsLoaded(false);\n setShowPlaceholder(true);\n return true;\n }, [clearTimer, fallbackSrc, srcKey, usingFallback]);\n\n const retry = useCallback(() => {\n clearTimer();\n setUsingFallback(false);\n setHasError(false);\n setIsLoaded(false);\n setShowPlaceholder(true);\n setRetryKey((prev) => prev + 1);\n }, [clearTimer]);\n\n useEffect(() => {\n if (!node || !node.complete || node.naturalWidth === 0) return;\n if (typeof requestAnimationFrame !== 'function') {\n handleLoad(node);\n return;\n }\n const rafId = requestAnimationFrame(() => handleLoad(node));\n return () => cancelAnimationFrame(rafId);\n }, [node, activeSrc, retryKey, handleLoad]);\n\n return {\n activeSrc,\n retryKey,\n isLoaded,\n showPlaceholder,\n hasError,\n imgRef: setNode,\n handleLoad,\n handleError,\n retry,\n };\n}\n","import { useEffect } from 'react';\nimport { blurService } from '../../blur/blurService';\n\ntype DebugWindow = Window & { blurService?: typeof blurService };\n\n/**\n * Development helper: exposes the shared `blurService` singleton as\n * `window.blurService` while mounted, for inspection in the browser console.\n * Does not augment the global `Window` type of consuming apps.\n */\nexport function BlurServiceDebugger() {\n useEffect(() => {\n if (typeof window === 'undefined') return undefined;\n const target = window as DebugWindow;\n target.blurService = blurService;\n return () => {\n if (target.blurService === blurService) {\n delete target.blurService;\n }\n };\n }, []);\n\n return null;\n}\n\nexport default BlurServiceDebugger;\n","import { EyeIcon as Eye, XIcon as X } from '../icons';\nimport type { ChangeEvent, PointerEvent as ReactPointerEvent } from 'react';\nimport { useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport type { UploadLocale } from '../../types';\nimport { normalizeColorInput } from '../../utils/color';\nimport { formatFileSize } from '../../utils/formatters';\nimport { useImageUploadContext } from '../context';\nimport { useDialog } from '../hooks/useDialog';\nimport { normalizeUploadLocale, resolveTranslations, type UploadTranslations } from '../i18n';\nimport type { CustomImageRenderer } from '../types';\nimport { drawImageToCanvas, sampleCanvasPixelHex } from '../utils/canvasSampler';\nimport { resolveSlotClass } from '../utils/slotStyles';\nimport { BlurColorControls } from './BlurColorControls';\nimport { BlurImage } from './BlurImage';\nimport { SaveButton } from './SaveButton';\n\nconst DEBOUNCE_MS = 250;\n\nexport interface BlurVisualizationModalProps {\n isOpen: boolean;\n onClose: () => void;\n imageUrl: string;\n blurDataUrl?: string;\n blurColor?: string;\n altText?: string;\n originalSize?: number;\n optimizedSize?: number | null;\n detectedColor?: string;\n onChangeColor?: (hex: string) => void;\n onUseDetectedColor?: () => void;\n onChangeAltText?: (altText: string) => void;\n locale?: UploadLocale;\n translations?: Partial<UploadTranslations>;\n renderImage?: CustomImageRenderer;\n unstyled?: boolean;\n}\n\nexport function BlurVisualizationModal({\n isOpen, onClose, imageUrl, blurDataUrl, blurColor, altText,\n originalSize, optimizedSize, detectedColor, onChangeColor,\n onUseDetectedColor, onChangeAltText, locale: propLocale,\n translations, renderImage, unstyled: propUnstyled,\n}: BlurVisualizationModalProps) {\n const ctx = useImageUploadContext();\n const isUnstyled = propUnstyled ?? ctx.unstyled;\n const locale = normalizeUploadLocale(propLocale || ctx.locale);\n const tModal = resolveTranslations(locale, translations || ctx.translations).blurModal;\n const cls = (defaultClass: string) => resolveSlotClass(defaultClass, isUnstyled);\n\n const { dialogRef, titleId } = useDialog({ isOpen, onClose });\n const textareaId = useId();\n\n const baseColor = useMemo(() => (blurColor || detectedColor || '#F5F5F5').toUpperCase(), [blurColor, detectedColor]);\n const [localColor, setLocalColor] = useState(baseColor);\n const [hexInput, setHexInput] = useState(baseColor.replace('#', ''));\n const [sampledColor, setSampledColor] = useState<string | null>(null);\n const [penModeActive, setPenModeActive] = useState(false);\n const [localAltText, setLocalAltText] = useState(altText || '');\n const liveCanvasRef = useRef<HTMLCanvasElement | null>(null);\n const colorTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const altTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const pendingColorRef = useRef<string | null>(null);\n const pendingAltRef = useRef<string | null>(null);\n\n useEffect(() => {\n if (!isOpen) return;\n setLocalColor(baseColor);\n setHexInput(baseColor.replace('#', ''));\n setLocalAltText(altText || '');\n }, [isOpen, baseColor, altText, blurDataUrl, imageUrl, blurColor]);\n\n useEffect(() => () => {\n if (colorTimerRef.current) clearTimeout(colorTimerRef.current);\n if (altTimerRef.current) clearTimeout(altTimerRef.current);\n }, []);\n\n useEffect(() => {\n if (!isOpen) return;\n const srcToLoad = imageUrl || blurDataUrl;\n if (!srcToLoad) return;\n const img = new window.Image();\n img.crossOrigin = 'anonymous';\n img.onload = () => drawImageToCanvas(img, liveCanvasRef);\n img.onerror = () => {\n if (blurDataUrl && srcToLoad !== blurDataUrl) {\n const fallbackImg = new window.Image();\n fallbackImg.onload = () => drawImageToCanvas(fallbackImg, liveCanvasRef);\n fallbackImg.src = blurDataUrl;\n }\n };\n img.src = srcToLoad;\n return () => { img.onload = null; img.onerror = null; };\n }, [imageUrl, blurDataUrl, isOpen]);\n\n useEffect(() => {\n if (!sampledColor) return;\n const timer = window.setTimeout(() => setSampledColor(null), 2000);\n return () => window.clearTimeout(timer);\n }, [sampledColor]);\n\n if (!isOpen || typeof document === 'undefined') return null;\n\n const scheduleColorEmit = (hex: string) => {\n pendingColorRef.current = hex;\n if (colorTimerRef.current) clearTimeout(colorTimerRef.current);\n colorTimerRef.current = setTimeout(() => {\n colorTimerRef.current = null;\n const next = pendingColorRef.current;\n pendingColorRef.current = null;\n if (next !== null) onChangeColor?.(next);\n }, DEBOUNCE_MS);\n };\n\n const scheduleAltEmit = (nextAlt: string) => {\n pendingAltRef.current = nextAlt;\n if (altTimerRef.current) clearTimeout(altTimerRef.current);\n altTimerRef.current = setTimeout(() => {\n altTimerRef.current = null;\n const next = pendingAltRef.current;\n pendingAltRef.current = null;\n if (next !== null) onChangeAltText?.(next);\n }, DEBOUNCE_MS);\n };\n\n const flushPendingChanges = () => {\n if (colorTimerRef.current) {\n clearTimeout(colorTimerRef.current);\n colorTimerRef.current = null;\n }\n if (pendingColorRef.current !== null) {\n onChangeColor?.(pendingColorRef.current);\n pendingColorRef.current = null;\n }\n if (altTimerRef.current) {\n clearTimeout(altTimerRef.current);\n altTimerRef.current = null;\n }\n if (pendingAltRef.current !== null) {\n onChangeAltText?.(pendingAltRef.current);\n pendingAltRef.current = null;\n }\n };\n\n const handleClose = () => {\n flushPendingChanges();\n onClose();\n };\n\n const syncLocalHex = (hex: string, notify = true) => {\n setLocalColor(hex);\n setHexInput(hex.replace('#', ''));\n if (notify) scheduleColorEmit(hex);\n };\n\n const handleColorPickerChange = (e: ChangeEvent<HTMLInputElement>) => syncLocalHex(e.target.value.toUpperCase());\n\n const handleHexInputChange = (event: ChangeEvent<HTMLInputElement>) => {\n const sanitized = event.target.value.replace(/[^0-9a-fA-F]/g, '').slice(0, 6);\n setHexInput(sanitized.toUpperCase());\n if (sanitized.length === 3 || sanitized.length === 6) {\n const normalized = normalizeColorInput(`#${sanitized}`);\n if (normalized) {\n setLocalColor(normalized);\n scheduleColorEmit(normalized);\n }\n }\n };\n\n const handlePenSample = (event: ReactPointerEvent<HTMLDivElement>) => {\n if (!penModeActive) {\n if (event.pointerType === 'pen') setPenModeActive(true);\n else return;\n }\n const sampled = sampleCanvasPixelHex(event, liveCanvasRef);\n if (!sampled) return;\n setSampledColor(sampled);\n syncLocalHex(sampled);\n };\n\n const handleUseDetectedColor = () => {\n if (!detectedColor) return;\n if (colorTimerRef.current) {\n clearTimeout(colorTimerRef.current);\n colorTimerRef.current = null;\n pendingColorRef.current = null;\n }\n const normalized = normalizeColorInput(detectedColor) || detectedColor.toUpperCase();\n setLocalColor(normalized);\n setHexInput(normalized.replace('#', ''));\n if (onUseDetectedColor) onUseDetectedColor();\n else onChangeColor?.(normalized);\n };\n\n const displayColor = localColor || blurColor || '#F5F5F5';\n\n return createPortal(\n <div\n data-slot=\"blur-modal-backdrop\"\n data-unstyled={isUnstyled || undefined}\n className={cls('iuk-modal-backdrop')}\n dir={locale === 'ar' ? 'rtl' : 'ltr'}\n onClick={handleClose}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n >\n <div\n ref={dialogRef}\n data-slot=\"blur-modal\"\n className={cls('iuk-blur-modal')}\n onClick={(e) => e.stopPropagation()}\n >\n <div className={cls('iuk-blur-modal__header')}>\n <div className={cls('iuk-blur-modal__title-row')}>\n <Eye size={20} className={cls('iuk-blur-modal__title-icon')} />\n <h2 id={titleId} className={cls('iuk-blur-modal__title')}>{tModal.title}</h2>\n {optimizedSize ? <span className={cls('iuk-badge')}>{formatFileSize(optimizedSize)}</span> : null}\n </div>\n <button type=\"button\" onClick={handleClose} className={cls('iuk-icon-btn')} aria-label={tModal.closeModal}>\n <X size={18} />\n </button>\n </div>\n\n <div className={cls('iuk-blur-modal__body')}>\n <div className={cls('iuk-blur-modal__grid')}>\n <BlurColorControls\n localColor={localColor} hexInput={hexInput} penModeActive={penModeActive}\n detectedColor={detectedColor} sampledColor={sampledColor} tModal={tModal}\n onColorPickerChange={handleColorPickerChange}\n onHexInputChange={handleHexInputChange}\n onTogglePenMode={() => setPenModeActive((prev) => !prev)}\n onUseDetectedColor={handleUseDetectedColor}\n />\n\n <div className={cls('iuk-blur-modal__preview-col')}>\n <h3 className={cls('iuk-blur-modal__section-title')}>{tModal.livePreview}</h3>\n <div\n className={cls(`iuk-blur-modal__stage ${penModeActive ? 'iuk-blur-modal__stage--sampling' : ''}`.trim())}\n style={{ backgroundColor: displayColor }}\n onPointerDown={handlePenSample}\n >\n <BlurImage\n src={imageUrl} alt={altText || tModal.livePreview}\n blurDataUrl={blurDataUrl} blurColor={displayColor}\n objectFit=\"contain\" renderImage={renderImage}\n onImageLoad={(img) => { if (img) drawImageToCanvas(img, liveCanvasRef); }}\n />\n {!blurDataUrl && <div className={cls('iuk-blur-modal__no-blur-note')}>{tModal.showingOriginal}</div>}\n </div>\n\n {optimizedSize && originalSize && originalSize > optimizedSize ? (\n <div className={cls('iuk-blur-modal__savings')}>\n <span>{tModal.saved}</span>\n <strong>\n {formatFileSize(originalSize - optimizedSize)} (\n {Math.round(((originalSize - optimizedSize) / originalSize) * 100)}%)\n </strong>\n </div>\n ) : null}\n </div>\n </div>\n\n <div className={cls('iuk-blur-modal__alt-section')}>\n <label htmlFor={textareaId} className={cls('iuk-blur-modal__section-title')}>\n {tModal.accessibility} — {tModal.altText}\n </label>\n <textarea\n id={textareaId}\n value={localAltText}\n onChange={(e) => { setLocalAltText(e.target.value); scheduleAltEmit(e.target.value); }}\n className={cls('iuk-blur-modal__textarea')}\n placeholder={tModal.altTextPlaceholder}\n rows={2}\n />\n </div>\n\n <canvas ref={liveCanvasRef} style={{ display: 'none' }} aria-hidden=\"true\" />\n </div>\n\n <div className={cls('iuk-blur-modal__footer')}>\n <SaveButton unstyled={isUnstyled} onClick={handleClose}>{tModal.saveAndClose}</SaveButton>\n </div>\n </div>\n </div>,\n document.body,\n );\n}\n\nexport default BlurVisualizationModal;\n","import type { PointerEvent as ReactPointerEvent, RefObject } from 'react';\nimport { rgbToHex } from '../../utils/color';\n\nexport function drawImageToCanvas(\n img: HTMLImageElement,\n canvasRef: RefObject<HTMLCanvasElement | null>,\n): void {\n const canvas = canvasRef.current;\n const ctx = canvas?.getContext('2d');\n if (!canvas || !ctx) return;\n const width = img.naturalWidth || img.width;\n const height = img.naturalHeight || img.height;\n if (!width || !height) return;\n canvas.width = width;\n canvas.height = height;\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n try {\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height);\n } catch {\n // Tainted cross-origin canvas ignored gracefully\n }\n}\n\nexport function sampleCanvasPixelHex(\n event: ReactPointerEvent<HTMLElement>,\n canvasRef: RefObject<HTMLCanvasElement | null>,\n): string | null {\n const canvas = canvasRef.current;\n const context = canvas?.getContext('2d');\n if (!canvas || !context || canvas.width === 0 || canvas.height === 0) {\n return null;\n }\n\n const rect = event.currentTarget.getBoundingClientRect();\n if (!rect.width || !rect.height) return null;\n\n const relX = (event.clientX - rect.left) / rect.width;\n const relY = (event.clientY - rect.top) / rect.height;\n if (relX < 0 || relY < 0 || relX > 1 || relY > 1) return null;\n\n const x = Math.min(\n Math.max(Math.floor(relX * canvas.width), 0),\n canvas.width - 1,\n );\n const y = Math.min(\n Math.max(Math.floor(relY * canvas.height), 0),\n canvas.height - 1,\n );\n\n let pixel: Uint8ClampedArray;\n try {\n pixel = context.getImageData(x, y, 1, 1).data;\n } catch {\n return null;\n }\n\n const [r, g, b, alpha] = pixel;\n if (alpha === 0) return null;\n\n return rgbToHex(r, g, b);\n}\n","import { PenToolIcon as PenTool, WandIcon as Wand2 } from '../icons';\nimport type { ChangeEvent } from 'react';\nimport type { BlurModalTranslations } from '../i18n';\n\nexport interface BlurColorControlsProps {\n localColor: string;\n hexInput: string;\n penModeActive: boolean;\n detectedColor?: string;\n sampledColor: string | null;\n tModal: BlurModalTranslations;\n onColorPickerChange: (event: ChangeEvent<HTMLInputElement>) => void;\n onHexInputChange: (event: ChangeEvent<HTMLInputElement>) => void;\n onTogglePenMode: () => void;\n onUseDetectedColor: () => void;\n}\n\nexport function BlurColorControls({\n localColor,\n hexInput,\n penModeActive,\n detectedColor,\n sampledColor,\n tModal,\n onColorPickerChange,\n onHexInputChange,\n onTogglePenMode,\n onUseDetectedColor,\n}: BlurColorControlsProps) {\n return (\n <div className=\"iuk-blur-modal__controls\">\n <h3 className=\"iuk-blur-modal__section-title\">{tModal.adjustColor}</h3>\n <p className=\"iuk-blur-modal__subtitle\">\n {penModeActive ? `🎨 ${tModal.clickToSample}` : tModal.pickColorNote}\n </p>\n\n <div className=\"iuk-blur-modal__picker-row\">\n <label className=\"iuk-blur-modal__color-well\">\n <input\n type=\"color\"\n value={localColor}\n onChange={onColorPickerChange}\n aria-label={tModal.adjustColor}\n />\n </label>\n\n <div className=\"iuk-blur-modal__hex-group\">\n <div className=\"iuk-blur-modal__hex-field\">\n <span>#</span>\n <input\n type=\"text\"\n value={hexInput}\n onChange={onHexInputChange}\n maxLength={6}\n spellCheck={false}\n aria-label={tModal.enterHexColor}\n placeholder={tModal.hexPlaceholder}\n />\n </div>\n <div className=\"iuk-blur-modal__swatch-chip\">\n <span\n className=\"iuk-blur-modal__swatch-dot\"\n style={{ backgroundColor: localColor }}\n aria-hidden=\"true\"\n />\n <code>{localColor}</code>\n </div>\n </div>\n </div>\n\n <div className=\"iuk-blur-modal__actions-row\">\n <button\n type=\"button\"\n onClick={onTogglePenMode}\n className={`iuk-btn iuk-btn--secondary ${penModeActive ? 'iuk-btn--active' : ''}`}\n aria-label={\n penModeActive ? tModal.disablePenMode : tModal.enablePenMode\n }\n >\n <PenTool size={14} />\n <span>\n {penModeActive ? tModal.penModeActive : tModal.enablePenMode}\n </span>\n </button>\n\n {detectedColor && (\n <button\n type=\"button\"\n className=\"iuk-btn iuk-btn--secondary\"\n onClick={onUseDetectedColor}\n >\n <Wand2 size={14} />\n <span>{tModal.resetToDetected}</span>\n <code>{detectedColor.toUpperCase()}</code>\n </button>\n )}\n\n {sampledColor && (\n <span className=\"iuk-badge iuk-badge--accent\">\n <PenTool size={12} />\n <span>\n {tModal.sampled} {sampledColor}\n </span>\n </span>\n )}\n </div>\n </div>\n );\n}\n","import type { ButtonHTMLAttributes, ReactNode } from 'react';\nimport { resolveSlotClass } from '../utils/slotStyles';\n\nexport interface SaveButtonProps\n extends ButtonHTMLAttributes<HTMLButtonElement> {\n icon?: ReactNode;\n unstyled?: boolean;\n children: ReactNode;\n}\n\nexport function SaveButton({\n icon,\n unstyled = false,\n children,\n className = '',\n type = 'button',\n ...rest\n}: SaveButtonProps) {\n return (\n <button\n type={type}\n className={resolveSlotClass('iuk-save-button', unstyled, className)}\n {...rest}\n >\n {icon && (\n <span className={resolveSlotClass('iuk-save-button__icon', unstyled)}>\n {icon}\n </span>\n )}\n <span>{children}</span>\n </button>\n );\n}\n\nexport default SaveButton;\n","import {\n ChevronUpIcon as ChevronUp,\n LoaderIcon as Loader2,\n MinusIcon as Minus,\n XIcon as X,\n} from '../icons';\nimport {\n type ForwardedRef,\n forwardRef,\n type ReactElement,\n type Ref,\n useEffect,\n useState,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport type { UploadPresetName } from '../../types';\nimport { useImageUploadContext } from '../context';\nimport { useDialog } from '../hooks/useDialog';\nimport { normalizeUploadLocale, resolveTranslations } from '../i18n';\nimport type {\n ImageUploadHandle,\n ImageUploadProps,\n MultiImageUploadProps,\n SingleImageUploadProps,\n} from '../types';\nimport { resolveSlotClass } from '../utils/slotStyles';\nimport { MultiImageUpload } from './MultiImageUpload';\nimport { SingleImageUpload } from './SingleImageUpload';\n\nfunction ImageUploadInner<TPreset extends string = UploadPresetName>(\n props: ImageUploadProps<TPreset>,\n ref: ForwardedRef<ImageUploadHandle>,\n) {\n const ctx = useImageUploadContext();\n const isUnstyled = props.unstyled ?? ctx.unstyled;\n const uploadLocale = normalizeUploadLocale(props.locale || ctx.locale);\n const ui = resolveTranslations(\n uploadLocale,\n props.translations || ctx.translations,\n );\n const dir = uploadLocale === 'ar' ? 'rtl' : 'ltr';\n const { isOpen, onClose, title, modeVariant } = props;\n const [isMinimized, setIsMinimized] = useState(false);\n const [dockNode, setDockNode] = useState<HTMLElement | null>(null);\n const cls = (defaultClass: string) => resolveSlotClass(defaultClass, isUnstyled);\n\n useEffect(() => {\n if (!isOpen) {\n setIsMinimized(false);\n }\n }, [isOpen]);\n\n const { dialogRef, titleId } = useDialog({\n isOpen: Boolean(isOpen) && !isMinimized,\n onClose,\n });\n\n useEffect(() => {\n if (typeof window === 'undefined' || !isOpen || !isMinimized) {\n setDockNode(null);\n return;\n }\n\n const updateDockReference = () => {\n const node = document.querySelector('[data-upload-progress-dock]');\n setDockNode((prev) =>\n node instanceof HTMLElement ? (node === prev ? prev : node) : null,\n );\n };\n\n updateDockReference();\n\n const observer = new MutationObserver(() => updateDockReference());\n observer.observe(document.body, {\n childList: true,\n subtree: true,\n });\n\n return () => observer.disconnect();\n }, [isOpen, isMinimized]);\n\n const content =\n props.mode === 'multiple' ? (\n <MultiImageUpload ref={ref} {...(props as MultiImageUploadProps<TPreset>)} />\n ) : (\n <SingleImageUpload ref={ref} {...(props as SingleImageUploadProps<TPreset>)} />\n );\n\n if (isOpen === undefined) {\n return (\n <div\n data-slot=\"upload-root\"\n data-unstyled={isUnstyled || undefined}\n className={cls('iuk-root')}\n dir={dir}\n data-upload-locale={uploadLocale}\n >\n {content}\n </div>\n );\n }\n\n if (!isOpen) return null;\n\n const minimizedButton = (\n <button\n type=\"button\"\n data-slot=\"minimized-pill\"\n className={cls('iuk-minimized-pill')}\n onClick={() => setIsMinimized(false)}\n title={ui.restoreUploadWindow}\n >\n <Loader2 size={16} className={cls('iuk-spin')} />\n <span className={cls('iuk-minimized-pill__copy')}>\n <span className={cls('iuk-minimized-pill__primary')}>{ui.uploadWindow}</span>\n <span className={cls('iuk-minimized-pill__secondary')}>{ui.tapToResume}</span>\n </span>\n <ChevronUp size={16} />\n </button>\n );\n\n return (\n <>\n <div\n data-slot=\"upload-modal-backdrop\"\n data-unstyled={isUnstyled || undefined}\n className={cls(\n `iuk-root iuk-modal-backdrop ${isMinimized ? 'iuk-modal-backdrop--hidden' : ''}`.trim(),\n )}\n dir={dir}\n data-upload-locale={uploadLocale}\n role=\"dialog\"\n aria-modal={!isMinimized}\n aria-hidden={isMinimized}\n aria-labelledby={title ? titleId : undefined}\n aria-label={!title ? ui.uploadWindow : undefined}\n onClick={() => onClose?.()}\n >\n <div\n ref={dialogRef}\n data-slot=\"upload-dialog\"\n className={cls(\n `iuk-upload-dialog ${isMinimized ? 'iuk-upload-dialog--hidden' : ''}`.trim(),\n )}\n onClick={(e) => e.stopPropagation()}\n >\n {onClose && (\n <div className={cls('iuk-upload-dialog__controls')}>\n <button\n type=\"button\"\n className={cls('iuk-icon-btn iuk-icon-btn--floating')}\n onClick={() => setIsMinimized(true)}\n aria-label={ui.minimize}\n title={ui.minimizeUploader}\n >\n <Minus size={18} />\n </button>\n <button\n type=\"button\"\n className={cls('iuk-icon-btn iuk-icon-btn--floating')}\n onClick={onClose}\n aria-label={ui.close}\n >\n <X size={18} />\n </button>\n </div>\n )}\n <div\n className={cls('iuk-upload-dialog__card')}\n onClick={(e) => e.stopPropagation()}\n >\n {title && (\n <h3 id={titleId} className={cls('iuk-upload-dialog__title')}>\n {modeVariant === 'edit'\n ? ui.editPrefix.replace('{title}', title)\n : title}\n </h3>\n )}\n {content}\n </div>\n </div>\n </div>\n\n {isMinimized &&\n typeof document !== 'undefined' &&\n (dockNode ? (\n createPortal(\n <div className={cls('iuk-minimized-portal')}>{minimizedButton}</div>,\n dockNode,\n )\n ) : (\n <div className={cls('iuk-minimized-dock')}>{minimizedButton}</div>\n ))}\n </>\n );\n}\n\nexport const ImageUpload = forwardRef(ImageUploadInner) as <\n TPreset extends string = UploadPresetName,\n>(\n props: ImageUploadProps<TPreset> & { ref?: Ref<ImageUploadHandle> },\n) => ReactElement | null;\n\nexport const UnifiedImageUpload = ImageUpload;\nexport default ImageUpload;\n","import {\n type ChangeEvent, type ForwardedRef, Fragment, forwardRef, type HTMLAttributes,\n type ReactElement, type Ref, useId, useImperativeHandle, useRef,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport type { UploadPresetName } from '../../types';\nimport { useImageUploadContext } from '../context';\nimport { useClipboardPaste } from '../hooks/useClipboardPaste';\nimport { useDragAndDrop } from '../hooks/useDragAndDrop';\nimport { useMultiImageState } from '../hooks/useMultiImageState';\nimport type { MultiUploadSlot } from '../styling';\nimport type { ImageUploadHandle, MultiImageUploadProps } from '../types';\nimport { HIDDEN_INPUT_STYLE, resolveSlotClass, resolveSlotStyle, resolveUploadDataState } from '../utils/slotStyles';\nimport { AltTextModal } from './AltTextModal';\nimport { MultiAddMoreTile, MultiEmptyDropzone } from './MultiDropzoneViews';\nimport { MultiFooterSection, MultiUploadHeaderAlerts } from './MultiUploadHeaderAlerts';\nimport { PreviewTile } from './PreviewTile';\nimport { QualitySelector } from './QualitySelector';\nimport { UploadProgressPanel, useRetainedProgressItems } from './UploadProgressPanel';\n\nconst DEFAULT_ACCEPT = 'image/jpeg,image/png,image/webp,image/avif,image/svg+xml';\nconst FOLDER_INPUT_ATTRS: Record<string, string> = { webkitdirectory: '', directory: '' };\n\nfunction MultiImageUploadInner<TPreset extends string = UploadPresetName>(\n props: MultiImageUploadProps<TPreset>,\n ref: ForwardedRef<ImageUploadHandle>,\n) {\n const {\n preset, translations, renderImage, label, error, helperText, className, style,\n recommendedQuality, qualityNote, isOpen, maxImages = 999,\n accept = DEFAULT_ACCEPT, allowFolder = true, disabled = false,\n required = false, blurType = 'card', showQualitySelector = true,\n capture, enablePaste = true, pasteTarget = 'dropzone', name, onBlur,\n classNames: cCls, styles: cSty,\n renderHeader, renderEmptyDropzone, renderTile, renderAddMore,\n } = props;\n\n const ctx = useImageUploadContext();\n const isUnstyled = props.unstyled ?? ctx.unstyled;\n const pCls = ctx.multiClassNames;\n const pSty = ctx.multiStyles;\n\n const slotClass = (slot: MultiUploadSlot, defaultClass?: string) =>\n resolveSlotClass(defaultClass, isUnstyled, pCls?.[slot], cCls?.[slot]);\n const slotStyle = (slot: MultiUploadSlot) =>\n resolveSlotStyle(pSty?.[slot], cSty?.[slot]);\n\n const state = useMultiImageState(props);\n const { locale, ui, previews, selectedPreviews, uploadingPreviews, imagesWithoutAlt, editingTarget } = state;\n\n const rootRef = useRef<HTMLDivElement>(null);\n const labelId = useId();\n const inputId = useId();\n const statusTextId = useId();\n const fileInputRef = useRef<HTMLInputElement>(null);\n const folderInputRef = useRef<HTMLInputElement>(null);\n\n const dockItems = useRetainedProgressItems(uploadingPreviews, previews);\n\n const { isDragging, dragHandlers } = useDragAndDrop({\n disabled, onDrop: (files) => void state.handleFileSelect(files),\n });\n\n const { onPaste } = useClipboardPaste({\n enabled: enablePaste, pasteTarget, disabled, multiple: true,\n onPasteFiles: (files) => { void state.handleFileSelect(files); },\n });\n\n const openFilePicker = () => { if (!disabled) fileInputRef.current?.click(); };\n const openFolderPicker = () => { if (!disabled) folderInputRef.current?.click(); };\n const selectAll = () => state.setSelectedPreviews(new Set(previews.map((p) => p.id)));\n const clearSelection = () => state.setSelectedPreviews(new Set());\n const retryFailed = () => void state.handleRetryFailed();\n\n useImperativeHandle(ref, () => ({\n focus: () => {\n const focusable = rootRef.current?.querySelector<HTMLElement>(\n '[data-slot=\"empty-dropzone\"], [data-slot=\"empty-actions\"] button, [data-slot=\"add-more\"] button',\n );\n (focusable ?? rootRef.current)?.focus();\n },\n open: openFilePicker,\n clear: () => state.handleClearAll(),\n }));\n\n const handleFilesInputChange = (e: ChangeEvent<HTMLInputElement>) => {\n if (e.target.files && e.target.files.length > 0) void state.handleFileSelect(e.target.files);\n e.target.value = '';\n };\n\n const displayError = error || state.validationError;\n const hasError = Boolean(displayError) || state.hasFailedUploads;\n const hasStatusText = Boolean(helperText || displayError);\n const visualState = resolveUploadDataState({\n disabled, hasError, isUploading: state.isUploading, isDragging, hasContent: previews.length > 0,\n });\n\n const dropzoneProps: HTMLAttributes<HTMLElement> & { 'data-state'?: string } = {\n ...dragHandlers, onPaste,\n role: 'button', tabIndex: disabled ? -1 : 0,\n 'aria-label': ui.selectFilesAria, 'aria-disabled': disabled || undefined,\n 'aria-required': required || undefined, 'aria-invalid': hasError || undefined,\n 'aria-describedby': hasStatusText ? statusTextId : undefined,\n 'data-state': visualState,\n onClick: () => { if (!disabled) openFilePicker(); },\n onKeyDown: (event) => {\n if (!disabled && (event.key === 'Enter' || event.key === ' ')) {\n event.preventDefault();\n openFilePicker();\n }\n },\n };\n\n const slotStylingProps = {\n unstyled: isUnstyled, providerClassNames: pCls, classNames: cCls, providerStyles: pSty, styles: cSty,\n };\n const hiddenInputClass = resolveSlotClass('iuk-hidden-input', isUnstyled);\n const hiddenInputStyle = isUnstyled ? HIDDEN_INPUT_STYLE : undefined;\n\n return (\n <>\n <div\n ref={rootRef} data-slot=\"multi-root\" data-state={visualState} data-unstyled={isUnstyled || undefined}\n className={resolveSlotClass('iuk-multi', isUnstyled, pCls?.root, cCls?.root, className)}\n style={resolveSlotStyle(pSty?.root, cSty?.root, style)} dir={locale === 'ar' ? 'rtl' : 'ltr'}\n onPaste={onPaste}\n onBlur={onBlur ? (e) => { if (!e.currentTarget.contains(e.relatedTarget as Node | null)) onBlur(); } : undefined}\n >\n {name && (\n <input type=\"hidden\" name={name} value={state.serializedFormValue} required={required} data-slot=\"form-input\" />\n )}\n\n {renderHeader ? (\n renderHeader({\n label, required, disabled, totalCount: previews.length,\n selectedCount: selectedPreviews.size, uploadingCount: uploadingPreviews.length,\n isUploading: state.isUploading, hasFailedUploads: state.hasFailedUploads,\n selectAll, clearSelection, removeSelected: state.handleRemoveSelected,\n retryFailed, locale, ui,\n })\n ) : (\n <MultiUploadHeaderAlerts\n label={label} labelId={labelId} inputId={inputId} required={required} disabled={disabled}\n totalCount={previews.length} selectedCount={selectedPreviews.size}\n uploadingCount={uploadingPreviews.length} missingAltCount={imagesWithoutAlt.length}\n isUploading={state.isUploading} hasFailedUploads={state.hasFailedUploads}\n infoMessage={state.infoMessage} showMissingAltWarning={state.showMissingAltWarning}\n uploadStats={state.uploadStats} locale={locale} translations={translations} ui={ui}\n onSelectAll={selectAll} onDeselectAll={clearSelection}\n onRemoveSelected={state.handleRemoveSelected} onRetryFailed={retryFailed} {...slotStylingProps}\n />\n )}\n\n {showQualitySelector && (\n <div data-slot=\"quality-selector\" className={slotClass('qualitySelector')} style={slotStyle('qualitySelector')}>\n <QualitySelector\n value={state.qualityLevel} onChange={state.setQualityLevel}\n preset={preset} recommendedLevel={recommendedQuality}\n recommendationNote={qualityNote} locale={locale}\n disabled={state.isUploading || disabled} unstyled={isUnstyled}\n />\n </div>\n )}\n\n <input\n id={inputId} ref={fileInputRef} type=\"file\" accept={accept} capture={capture}\n onChange={handleFilesInputChange} className={hiddenInputClass} style={hiddenInputStyle}\n disabled={disabled} multiple aria-label={ui.selectFilesAria}\n aria-invalid={hasError || undefined}\n aria-describedby={hasStatusText ? statusTextId : undefined}\n />\n <input\n ref={folderInputRef} type=\"file\" accept={accept} onChange={handleFilesInputChange}\n className={hiddenInputClass} style={hiddenInputStyle}\n disabled={disabled} {...FOLDER_INPUT_ATTRS} aria-label={ui.selectFolderAria}\n />\n\n {previews.length === 0 ? (\n renderEmptyDropzone ? (\n renderEmptyDropzone({\n state: visualState, isDragging, disabled, allowFolder,\n maxSizeMB: state.maxSizeMB, maxImages, error: displayError || undefined,\n openFileDialog: openFilePicker, openFolderDialog: openFolderPicker,\n dropzoneProps, locale, ui,\n })\n ) : (\n <MultiEmptyDropzone\n isDragging={isDragging} disabled={disabled} hasError={Boolean(displayError)}\n required={required} enablePaste={enablePaste}\n visualState={visualState} allowFolder={allowFolder} maxSizeMB={state.maxSizeMB}\n ui={ui} dragHandlers={dragHandlers} onPaste={onPaste}\n onSelectFiles={openFilePicker} onSelectFolder={openFolderPicker} {...slotStylingProps}\n />\n )\n ) : (\n <div data-slot=\"grid\" className={slotClass('grid', 'iuk-multi__grid')} style={slotStyle('grid')}>\n {previews.map((item, index) =>\n renderTile ? (\n <Fragment key={item.id}>\n {renderTile({\n item, index, isSelected: selectedPreviews.has(item.id), disabled,\n toggleSelect: () => state.toggleSelect(item.id),\n remove: () => state.handleRemove(item.id),\n cancel: () => state.handleCancelUpload(item.id),\n retry: () => void state.handleRetryUpload(item.id),\n openAltTextModal: () => state.setEditingAltTextId(item.id),\n setAltText: (altText) => state.handleAltTextSave(item.id, altText),\n setBlurColor: (hex) => state.handleColorChange(item.id, hex),\n locale, ui,\n })}\n </Fragment>\n ) : (\n <PreviewTile\n key={item.id} preview={item} onRemove={state.handleRemove}\n onCancel={state.handleCancelUpload}\n onRetry={(id) => void state.handleRetryUpload(id)}\n disabled={disabled} blurType={blurType} isSelected={selectedPreviews.has(item.id)}\n onToggleSelect={state.toggleSelect} onEditAltText={(id) => state.setEditingAltTextId(id)}\n onChangeAltText={state.handleAltTextSave} onChangeColor={state.handleColorChange}\n locale={locale} translations={translations} renderImage={renderImage}\n unstyled={isUnstyled} className={slotClass('tile')} style={slotStyle('tile')}\n />\n ),\n )}\n\n {renderAddMore ? (\n renderAddMore({\n isDragging, disabled, allowFolder,\n remainingCount: Math.max(0, maxImages - previews.length),\n openFileDialog: openFilePicker, openFolderDialog: openFolderPicker,\n dropzoneProps, locale, ui,\n })\n ) : (\n <MultiAddMoreTile\n isDragging={isDragging} disabled={disabled} allowFolder={allowFolder} ui={ui}\n dragHandlers={dragHandlers} onSelectFiles={openFilePicker} onSelectFolder={openFolderPicker}\n {...slotStylingProps}\n />\n )}\n </div>\n )}\n\n <MultiFooterSection\n helperText={helperText} displayError={displayError} statusTextId={statusTextId} isOpen={isOpen}\n hasPreviews={previews.length > 0} hasCompletedPreviews={state.completedPreviews.length > 0}\n isUploading={state.isUploading} disabled={disabled} requireAltText={state.requireAltText}\n missingAltCount={imagesWithoutAlt.length} onSave={state.handleSaveImages} ui={ui} {...slotStylingProps}\n />\n </div>\n\n {editingTarget && (\n <AltTextModal\n imageUrl={editingTarget.url} initialAltText={editingTarget.altText}\n onSave={(nextAlt) => state.handleAltTextSave(editingTarget.id, nextAlt)}\n onClose={() => state.setEditingAltTextId(null)}\n locale={locale} translations={translations} renderImage={renderImage} unstyled={isUnstyled}\n />\n )}\n\n {typeof document !== 'undefined' && dockItems.length > 0 &&\n createPortal(\n <UploadProgressPanel\n items={dockItems} completedCount={state.uploadStats.completed}\n totalCount={state.uploadStats.total} locale={locale}\n translations={translations} renderImage={renderImage} unstyled={isUnstyled}\n />,\n document.body,\n )}\n </>\n );\n}\n\nexport const MultiImageUpload = forwardRef(MultiImageUploadInner) as <\n TPreset extends string = UploadPresetName,\n>(\n props: MultiImageUploadProps<TPreset> & { ref?: Ref<ImageUploadHandle> },\n) => ReactElement | null;\n\nexport default MultiImageUpload;\n","import {\n FolderOpenIcon as FolderOpen,\n ImagePlusIcon as ImagePlus,\n UploadIcon as Upload,\n} from '../icons';\nimport type { DragEvent } from 'react';\nimport type { UploadTranslations } from '../i18n';\nimport type {\n MultiUploadClassNames,\n MultiUploadSlot,\n MultiUploadStyles,\n UploadVisualState,\n} from '../styling';\nimport {\n cx,\n resolveSlotClass,\n resolveSlotStyle,\n resolveUploadDataState,\n} from '../utils/slotStyles';\n\nexport interface DropzoneDragHandlers {\n onDragEnter: (e: DragEvent) => void;\n onDragLeave: (e: DragEvent) => void;\n onDragOver: (e: DragEvent) => void;\n onDrop: (e: DragEvent) => void;\n}\n\nexport interface MultiDropzoneSlotProps {\n unstyled?: boolean;\n providerClassNames?: MultiUploadClassNames;\n classNames?: MultiUploadClassNames;\n providerStyles?: MultiUploadStyles;\n styles?: MultiUploadStyles;\n}\n\nexport interface MultiEmptyDropzoneProps extends MultiDropzoneSlotProps {\n isDragging: boolean;\n disabled?: boolean;\n hasError?: boolean;\n required?: boolean;\n enablePaste?: boolean;\n visualState?: UploadVisualState;\n allowFolder?: boolean;\n maxSizeMB: number;\n ui: UploadTranslations;\n dragHandlers: DropzoneDragHandlers;\n onPaste?: (e: React.ClipboardEvent<HTMLElement>) => void;\n onSelectFiles: () => void;\n onSelectFolder: () => void;\n}\n\nexport function MultiEmptyDropzone({\n isDragging,\n disabled = false,\n hasError = false,\n required = false,\n enablePaste = true,\n visualState: propVisualState,\n allowFolder = true,\n maxSizeMB,\n ui,\n dragHandlers,\n onPaste,\n onSelectFiles,\n onSelectFolder,\n unstyled,\n providerClassNames: pCls,\n classNames: cCls,\n providerStyles: pSty,\n styles: cSty,\n}: MultiEmptyDropzoneProps) {\n const visualState =\n propVisualState ?? resolveUploadDataState({ disabled, hasError, isDragging });\n\n const slotClass = (slot: MultiUploadSlot, defaultClass?: string) =>\n resolveSlotClass(defaultClass, unstyled, pCls?.[slot], cCls?.[slot]);\n const slotStyle = (slot: MultiUploadSlot) =>\n resolveSlotStyle(pSty?.[slot], cSty?.[slot]);\n\n const rootClassName = resolveSlotClass(\n cx(\n 'iuk-multi__empty',\n isDragging && 'iuk-multi__empty--dragging',\n disabled && 'iuk-multi__empty--disabled',\n hasError && 'iuk-multi__empty--error',\n ),\n unstyled,\n pCls?.emptyDropzone, cCls?.emptyDropzone,\n isDragging && pCls?.emptyDropzoneDragging, isDragging && cCls?.emptyDropzoneDragging,\n disabled && pCls?.emptyDropzoneDisabled, disabled && cCls?.emptyDropzoneDisabled,\n hasError && pCls?.emptyDropzoneError, hasError && cCls?.emptyDropzoneError,\n );\n\n const rootStyle = resolveSlotStyle(\n pSty?.emptyDropzone, cSty?.emptyDropzone,\n isDragging ? pSty?.emptyDropzoneDragging : undefined,\n isDragging ? cSty?.emptyDropzoneDragging : undefined,\n disabled ? pSty?.emptyDropzoneDisabled : undefined,\n disabled ? cSty?.emptyDropzoneDisabled : undefined,\n hasError ? pSty?.emptyDropzoneError : undefined,\n hasError ? cSty?.emptyDropzoneError : undefined,\n );\n\n return (\n <div\n data-slot=\"empty-dropzone\"\n data-state={visualState}\n data-dragging={isDragging || undefined}\n data-disabled={disabled || undefined}\n data-error={hasError || undefined}\n tabIndex={disabled ? -1 : 0}\n aria-required={required || undefined}\n aria-invalid={hasError || undefined}\n className={rootClassName}\n style={rootStyle}\n onPaste={onPaste}\n {...dragHandlers}\n >\n <div className={resolveSlotClass('iuk-dropzone__prompt', unstyled)}>\n <div className={resolveSlotClass('iuk-dropzone__icon', unstyled)}>\n <ImagePlus size={40} strokeWidth={1.5} />\n </div>\n <h3\n data-slot=\"empty-title\"\n className={slotClass('emptyTitle', 'iuk-multi__title')}\n style={slotStyle('emptyTitle')}\n >\n {isDragging ? ui.dropImagesHere : ui.uploadImages}\n </h3>\n <p\n data-slot=\"empty-hint\"\n className={slotClass('emptyHint', 'iuk-dropzone__hint')}\n style={slotStyle('emptyHint')}\n >\n {isDragging\n ? ui.releaseToUpload\n : `${ui.dragDropOrChoose}${enablePaste ? ` (${ui.pasteHint})` : ''}`}\n </p>\n\n {!isDragging && (\n <div\n data-slot=\"empty-actions\"\n className={slotClass('emptyActions', 'iuk-multi__btn-row')}\n style={slotStyle('emptyActions')}\n >\n <button\n type=\"button\"\n onClick={onSelectFiles}\n className={slotClass('primaryButton', 'iuk-btn iuk-btn--primary')}\n style={slotStyle('primaryButton')}\n disabled={disabled}\n >\n <Upload size={16} />\n <span>{ui.selectFiles}</span>\n </button>\n {allowFolder && (\n <button\n type=\"button\"\n onClick={onSelectFolder}\n className={slotClass('secondaryButton', 'iuk-btn iuk-btn--secondary')}\n style={slotStyle('secondaryButton')}\n disabled={disabled}\n >\n <FolderOpen size={16} />\n <span>{ui.selectFolder}</span>\n </button>\n )}\n </div>\n )}\n\n {!isDragging && (\n <p\n data-slot=\"empty-subtext\"\n className={slotClass('emptySubtext', 'iuk-multi__subtext')}\n style={slotStyle('emptySubtext')}\n >\n {ui.supportsFormats} •{' '}\n {ui.maxPerFile.replace('{size}', String(maxSizeMB))}\n </p>\n )}\n </div>\n </div>\n );\n}\n\nexport interface MultiAddMoreTileProps extends MultiDropzoneSlotProps {\n isDragging: boolean;\n disabled?: boolean;\n allowFolder?: boolean;\n ui: UploadTranslations;\n dragHandlers: DropzoneDragHandlers;\n onSelectFiles: () => void;\n onSelectFolder: () => void;\n}\n\nexport function MultiAddMoreTile({\n isDragging,\n disabled = false,\n allowFolder = true,\n ui,\n dragHandlers,\n onSelectFiles,\n onSelectFolder,\n unstyled,\n providerClassNames: pCls,\n classNames: cCls,\n providerStyles: pSty,\n styles: cSty,\n}: MultiAddMoreTileProps) {\n const slotClass = (slot: MultiUploadSlot, defaultClass?: string) =>\n resolveSlotClass(defaultClass, unstyled, pCls?.[slot], cCls?.[slot]);\n const slotStyle = (slot: MultiUploadSlot) =>\n resolveSlotStyle(pSty?.[slot], cSty?.[slot]);\n\n const rootClassName = resolveSlotClass(\n cx(\n 'iuk-tile iuk-tile--add-more',\n isDragging && 'iuk-tile--dragging',\n disabled && 'iuk-tile--disabled',\n ),\n unstyled,\n pCls?.addMoreTile, cCls?.addMoreTile,\n isDragging && pCls?.addMoreTileDragging, isDragging && cCls?.addMoreTileDragging,\n );\n\n const rootStyle = resolveSlotStyle(\n pSty?.addMoreTile, cSty?.addMoreTile,\n isDragging ? pSty?.addMoreTileDragging : undefined,\n isDragging ? cSty?.addMoreTileDragging : undefined,\n );\n\n return (\n <div\n data-slot=\"add-more\"\n data-dragging={isDragging || undefined}\n data-disabled={disabled || undefined}\n className={rootClassName}\n style={rootStyle}\n {...dragHandlers}\n >\n <div\n data-slot=\"add-more-content\"\n className={slotClass('addMoreContent', 'iuk-tile__add-content')}\n style={slotStyle('addMoreContent')}\n >\n <ImagePlus size={28} strokeWidth={1.5} />\n <p>{isDragging ? ui.dropHere : ui.addMore}</p>\n {!isDragging && (\n <div\n data-slot=\"add-more-actions\"\n className={slotClass('addMoreActions', 'iuk-tile__add-btns')}\n style={slotStyle('addMoreActions')}\n >\n <button\n type=\"button\"\n onClick={onSelectFiles}\n className={slotClass('secondaryButton', 'iuk-btn iuk-btn--secondary iuk-btn--sm')}\n style={slotStyle('secondaryButton')}\n disabled={disabled}\n >\n <Upload size={13} />\n <span>{ui.files}</span>\n </button>\n {allowFolder && (\n <button\n type=\"button\"\n onClick={onSelectFolder}\n className={slotClass('secondaryButton', 'iuk-btn iuk-btn--secondary iuk-btn--sm')}\n style={slotStyle('secondaryButton')}\n disabled={disabled}\n >\n <FolderOpen size={13} />\n <span>{ui.folder}</span>\n </button>\n )}\n </div>\n )}\n </div>\n </div>\n );\n}\n","import {\n AlertTriangleIcon as AlertTriangle,\n CheckCircleIcon as CheckCircle2,\n LoaderIcon as Loader2,\n SaveIcon as Save,\n TrashIcon as Trash2,\n XCircleIcon as XCircle,\n} from '../icons';\nimport type { MultiUploadStats } from '../hooks/useMultiImageState';\nimport {\n formatNeedsAltMessage,\n formatUploadingCount,\n type UploadLocale,\n type UploadTranslations,\n} from '../i18n';\nimport type {\n MultiUploadClassNames, MultiUploadSlot, MultiUploadStyles,\n} from '../styling';\nimport { cx, resolveSlotClass, resolveSlotStyle } from '../utils/slotStyles';\nimport { SaveButton } from './SaveButton';\n\nexport interface MultiSlotStylingProps {\n unstyled?: boolean;\n providerClassNames?: MultiUploadClassNames;\n classNames?: MultiUploadClassNames;\n providerStyles?: MultiUploadStyles;\n styles?: MultiUploadStyles;\n}\n\nexport interface MultiUploadHeaderAlertsProps extends MultiSlotStylingProps {\n label?: string;\n labelId?: string;\n inputId?: string;\n required?: boolean;\n disabled?: boolean;\n totalCount: number;\n selectedCount: number;\n uploadingCount: number;\n missingAltCount: number;\n isUploading: boolean;\n hasFailedUploads: boolean;\n infoMessage: string;\n showMissingAltWarning: boolean;\n uploadStats: MultiUploadStats;\n locale?: UploadLocale;\n translations?: Partial<UploadTranslations>;\n ui: UploadTranslations;\n onSelectAll: () => void;\n onDeselectAll: () => void;\n onRemoveSelected: () => void;\n onRetryFailed: () => void;\n}\n\nexport function MultiUploadHeaderAlerts({\n label, labelId, inputId, required = false, disabled = false,\n totalCount, selectedCount, uploadingCount, missingAltCount,\n isUploading, hasFailedUploads, infoMessage, showMissingAltWarning,\n uploadStats, locale = 'en', translations, ui,\n onSelectAll, onDeselectAll, onRemoveSelected, onRetryFailed,\n unstyled, providerClassNames, classNames, providerStyles, styles,\n}: MultiUploadHeaderAlertsProps) {\n const slotClass = (slot: MultiUploadSlot, defaultClass?: string) =>\n resolveSlotClass(defaultClass, unstyled, providerClassNames?.[slot], classNames?.[slot]);\n const slotStyle = (slot: MultiUploadSlot) =>\n resolveSlotStyle(providerStyles?.[slot], styles?.[slot]);\n\n return (\n <>\n <div data-slot=\"header\" className={slotClass('header', 'iuk-multi__header')} style={slotStyle('header')}>\n {(label || ui.uploadImages) && (\n <label\n id={labelId}\n htmlFor={inputId}\n data-slot=\"label\"\n className={slotClass('label', 'iuk-label')}\n style={slotStyle('label')}\n >\n <span>{label || ui.uploadImages}</span>\n {required && <span className={resolveSlotClass('iuk-required', unstyled)}>*</span>}\n {totalCount > 0 && (\n <span data-slot=\"count\" className={slotClass('count', 'iuk-multi__count')} style={slotStyle('count')}>\n ({totalCount})\n </span>\n )}\n </label>\n )}\n\n {totalCount > 0 && (\n <div data-slot=\"bulk-actions\" className={slotClass('bulkActions', 'iuk-multi__bulk')} style={slotStyle('bulkActions')}>\n {selectedCount === 0 ? (\n <button\n type=\"button\" onClick={onSelectAll} disabled={disabled}\n className={slotClass('bulkButton', 'iuk-btn iuk-btn--secondary iuk-btn--sm')}\n style={slotStyle('bulkButton')}\n >\n {ui.selectAll}\n </button>\n ) : (\n <>\n <button\n type=\"button\" onClick={onDeselectAll} disabled={disabled}\n className={slotClass('bulkButton', 'iuk-btn iuk-btn--secondary iuk-btn--sm')}\n style={slotStyle('bulkButton')}\n >\n {ui.deselectAll} ({selectedCount})\n </button>\n <button\n type=\"button\" onClick={onRemoveSelected} disabled={disabled}\n className={slotClass('bulkDangerButton', 'iuk-btn iuk-btn--danger iuk-btn--sm')}\n style={slotStyle('bulkDangerButton')}\n >\n <Trash2 size={14} />\n <span>{ui.removeSelected}</span>\n </button>\n </>\n )}\n </div>\n )}\n </div>\n\n {isUploading && (\n <div\n data-slot=\"alert\"\n role=\"status\"\n aria-live=\"polite\"\n className={slotClass('alert', 'iuk-alert iuk-alert--info')}\n style={slotStyle('alert')}\n >\n <span className={resolveSlotClass('iuk-alert__row', unstyled)}>\n <Loader2 size={16} className={resolveSlotClass('iuk-spin', unstyled)} />\n <span>{formatUploadingCount(ui, uploadingCount, locale, translations)}...</span>\n </span>\n {uploadStats.total > 0 && (\n <strong>\n {uploadStats.completed + uploadStats.failed} / {uploadStats.total}\n </strong>\n )}\n </div>\n )}\n\n {hasFailedUploads && (\n <div\n data-slot=\"alert\"\n role=\"alert\"\n className={slotClass('alert', 'iuk-alert iuk-alert--error')}\n style={slotStyle('alert')}\n >\n <XCircle size={16} />\n <span>\n {ui.someUploadsFailed}{' '}\n <button\n type=\"button\"\n onClick={onRetryFailed}\n disabled={isUploading || disabled}\n className={resolveSlotClass('iuk-link-btn', unstyled)}\n >\n {ui.retryFailedUploads}\n </button>\n </span>\n </div>\n )}\n\n {infoMessage && (\n <div\n data-slot=\"alert\"\n role=\"status\"\n className={slotClass('alert', 'iuk-alert iuk-alert--success')}\n style={slotStyle('alert')}\n >\n <CheckCircle2 size={16} />\n <span>{infoMessage}</span>\n </div>\n )}\n\n {showMissingAltWarning && missingAltCount > 0 && (\n <div\n data-slot=\"alert\"\n role=\"alert\"\n className={slotClass('alert', 'iuk-alert iuk-alert--warning')}\n style={slotStyle('alert')}\n >\n <AlertTriangle size={16} />\n <span>{formatNeedsAltMessage(ui, missingAltCount, locale)}</span>\n </div>\n )}\n </>\n );\n}\n\nexport interface MultiFooterSectionProps extends MultiSlotStylingProps {\n helperText?: string;\n displayError?: string;\n statusTextId?: string;\n isOpen?: boolean;\n hasPreviews: boolean;\n hasCompletedPreviews: boolean;\n isUploading: boolean;\n disabled: boolean;\n requireAltText: boolean;\n missingAltCount: number;\n onSave: () => void;\n ui: UploadTranslations;\n}\n\nexport function MultiFooterSection({\n helperText, displayError, statusTextId, isOpen, hasPreviews, hasCompletedPreviews,\n isUploading, disabled, requireAltText, missingAltCount, onSave, ui,\n unstyled, providerClassNames, classNames, providerStyles, styles,\n}: MultiFooterSectionProps) {\n const slotClass = (slot: MultiUploadSlot, defaultClass?: string) =>\n resolveSlotClass(defaultClass, unstyled, providerClassNames?.[slot], classNames?.[slot]);\n const slotStyle = (slot: MultiUploadSlot) =>\n resolveSlotStyle(providerStyles?.[slot], styles?.[slot]);\n\n return (\n <>\n {(helperText || displayError) && (\n <p\n id={statusTextId}\n role={displayError ? 'alert' : undefined}\n data-slot={displayError ? 'error-text' : 'helper-text'}\n className={resolveSlotClass(\n cx('iuk-helper-text', Boolean(displayError) && 'iuk-helper-text--error'),\n unstyled,\n providerClassNames?.helperText, classNames?.helperText,\n Boolean(displayError) && providerClassNames?.errorText,\n Boolean(displayError) && classNames?.errorText,\n )}\n style={resolveSlotStyle(\n providerStyles?.helperText, styles?.helperText,\n displayError ? providerStyles?.errorText : undefined,\n displayError ? styles?.errorText : undefined,\n )}\n >\n {displayError || helperText}\n </p>\n )}\n\n {isOpen && hasPreviews && (\n <div data-slot=\"commit-bar\" className={slotClass('commitBar', 'iuk-commit-bar')} style={slotStyle('commitBar')}>\n {requireAltText && missingAltCount > 0 && (\n <div className={resolveSlotClass('iuk-badge iuk-badge--warning', unstyled)}>\n <AlertTriangle size={13} />\n <span>{ui.withoutAltText.replace('{count}', String(missingAltCount))}</span>\n </div>\n )}\n <SaveButton\n unstyled={unstyled}\n className={slotClass('saveButton')}\n style={slotStyle('saveButton')}\n onClick={onSave}\n disabled={\n isUploading || disabled || !hasCompletedPreviews ||\n (requireAltText && missingAltCount > 0)\n }\n icon={<Save size={16} />}\n >\n {ui.saveImages}\n </SaveButton>\n </div>\n )}\n </>\n );\n}\n","import {\n CheckCircleIcon as CheckCircle2,\n LoaderIcon as Loader2,\n PaletteIcon as Palette,\n TypeIcon,\n XIcon as X,\n XCircleIcon as XCircle,\n} from '../icons';\nimport { type CSSProperties, useMemo, useState } from 'react';\nimport type { BlurPlaceholderType } from '../../blur/types';\nimport type { UploadLocale } from '../../types';\nimport { useImageUploadContext } from '../context';\nimport { useBlurDataURL } from '../hooks/useBlurService';\nimport {\n normalizeUploadLocale,\n resolveTranslations,\n type UploadTranslations,\n} from '../i18n';\nimport type { CustomImageRenderer, ImagePreview } from '../types';\nimport { appendCacheBuster } from '../utils/sessionMetaCache';\nimport { cx, resolveSlotClass, resolveUploadDataState } from '../utils/slotStyles';\nimport { BlurImage } from './BlurImage';\nimport { BlurVisualizationModal } from './BlurVisualizationModal';\n\nexport interface PreviewTileProps {\n preview: ImagePreview;\n onRemove: (id: string) => void;\n onCancel?: (id: string) => void;\n onRetry?: (id: string) => void;\n disabled?: boolean;\n blurType?: BlurPlaceholderType;\n isSelected?: boolean;\n onToggleSelect?: (id: string) => void;\n onEditAltText?: (id: string) => void;\n showCheckbox?: boolean;\n onAdjustColor?: (id: string) => void;\n onChangeColor?: (id: string, color: string) => void;\n onChangeAltText?: (id: string, altText: string) => void;\n appendCacheBuster?: boolean;\n locale?: UploadLocale;\n translations?: Partial<UploadTranslations>;\n renderImage?: CustomImageRenderer;\n unstyled?: boolean;\n className?: string;\n style?: CSSProperties;\n}\n\nexport function PreviewTile({\n preview, onRemove, onCancel, onRetry, disabled = false, blurType = 'card', isSelected = false,\n onToggleSelect, onEditAltText, showCheckbox = true, onAdjustColor,\n onChangeColor, onChangeAltText, appendCacheBuster: appendBuster = false,\n locale: propLocale, translations, renderImage,\n unstyled: propUnstyled, className, style,\n}: PreviewTileProps) {\n const ctx = useImageUploadContext();\n const isUnstyled = propUnstyled ?? ctx.unstyled;\n const locale = normalizeUploadLocale(propLocale || ctx.locale);\n const ui = resolveTranslations(locale, translations || ctx.translations);\n const [showBlurModal, setShowBlurModal] = useState(false);\n const cls = (defaultClass: string) => resolveSlotClass(defaultClass, isUnstyled);\n\n const isSvg = Boolean(\n preview.url?.toLowerCase().includes('.svg') ||\n preview.data?.format === 'svg' ||\n preview.url?.includes('image/svg+xml'),\n );\n\n const displayUrl = useMemo(\n () =>\n appendCacheBuster(preview.url, {\n enabled: appendBuster,\n token: preview.data?.contentHash || preview.data?.uploadedAt,\n }),\n [preview.url, preview.data?.contentHash, preview.data?.uploadedAt, appendBuster],\n );\n\n const fallbackBlurDataURL = useBlurDataURL(preview.url, { type: blurType, size: 'small' });\n const actualBlurDataUrl = preview.data?.blurDataUrl || fallbackBlurDataURL;\n const actualBlurColor = preview.blurColor || preview.data?.blurColor;\n\n const isUploading = Boolean(preview.isUploading);\n const hasError = Boolean(preview.error);\n const visualState = resolveUploadDataState({\n disabled, hasError, isUploading, hasContent: true,\n });\n const isSuccess = Boolean(\n !isUploading && !hasError && preview.originalSize && preview.optimizedSize,\n );\n const reductionPercent =\n isSuccess && preview.originalSize && preview.optimizedSize\n ? Math.round(\n ((preview.originalSize - preview.optimizedSize) / preview.originalSize) * 100,\n )\n : 0;\n\n return (\n <div\n data-slot=\"tile\"\n data-state={visualState}\n data-selected={isSelected || undefined}\n data-uploading={isUploading || undefined}\n data-error={hasError || undefined}\n className={resolveSlotClass(\n cx('iuk-tile', isSelected && 'iuk-tile--selected', hasError && 'iuk-tile--error'),\n isUnstyled,\n className,\n )}\n style={style}\n onClick={() => onToggleSelect && !disabled && onToggleSelect(preview.id)}\n >\n <div data-slot=\"tile-media\" className={cls('iuk-tile__media')}>\n <BlurImage\n src={displayUrl}\n alt={preview.altText || ui.previewAlt}\n blurDataUrl={!isSvg ? actualBlurDataUrl : undefined}\n blurColor={actualBlurColor}\n blurHash={preview.data?.blurHash}\n objectFit={isSvg ? 'contain' : 'cover'}\n style={isSvg ? { padding: '8px' } : undefined}\n renderImage={renderImage}\n />\n\n {showCheckbox && !disabled && !isUploading && onToggleSelect && (\n <div\n data-slot=\"tile-checkbox\"\n className={cls('iuk-tile__checkbox')}\n onClick={(e) => e.stopPropagation()}\n >\n <input\n type=\"checkbox\"\n checked={isSelected}\n onChange={() => onToggleSelect(preview.id)}\n aria-label={ui.selectImageAria}\n />\n </div>\n )}\n\n {!disabled && onEditAltText && (\n <button\n type=\"button\"\n data-slot=\"tile-alt-btn\"\n className={cls(\n cx(\n 'iuk-tile__action iuk-tile__action--alt',\n Boolean(preview.altText) && 'iuk-tile__action--has-alt',\n ),\n )}\n onClick={(e) => {\n e.stopPropagation();\n onEditAltText(preview.id);\n }}\n aria-label={preview.altText ? ui.editAltTextAria : ui.addAltTextAria}\n title={\n preview.altText\n ? ui.editPrefix.replace('{title}', preview.altText)\n : ui.addDescriptionForA11y\n }\n >\n {preview.altText ? <CheckCircle2 size={14} /> : <TypeIcon size={14} />}\n </button>\n )}\n\n {!disabled && !isUploading && (\n <button\n type=\"button\"\n data-slot=\"tile-blur-btn\"\n className={cls('iuk-tile__action iuk-tile__action--blur')}\n onClick={(e) => {\n e.stopPropagation();\n if (onAdjustColor) onAdjustColor(preview.id);\n else setShowBlurModal(true);\n }}\n aria-label={ui.adjustBlurColorAria}\n title={ui.adjustBlurColorTitle}\n >\n <Palette size={14} />\n </button>\n )}\n\n {!disabled && !isUploading && (\n <button\n type=\"button\"\n data-slot=\"tile-remove-btn\"\n className={cls('iuk-tile__action iuk-tile__action--remove')}\n onClick={(e) => {\n e.stopPropagation();\n onRemove(preview.id);\n }}\n aria-label={ui.removeImageAria}\n >\n <X size={15} />\n </button>\n )}\n\n {isUploading && (\n <div data-slot=\"tile-overlay\" className={cls('iuk-tile__overlay')}>\n <Loader2 size={24} className={cls('iuk-spin')} />\n <p className={cls('iuk-tile__status')}>\n {preview.uploadMessage || `${ui.uploading}...`}\n </p>\n {preview.progress !== undefined && preview.progress > 0 && (\n <div\n role=\"progressbar\"\n aria-valuenow={Math.round(preview.progress)}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={ui.uploading}\n className={cls('iuk-progress-bar')}\n >\n <div\n className={cls('iuk-progress-bar__fill')}\n style={{ width: `${preview.progress}%` }}\n />\n </div>\n )}\n {!disabled && (\n <button\n type=\"button\"\n data-slot=\"tile-cancel\"\n className={cls('iuk-btn iuk-btn--secondary iuk-btn--sm iuk-tile__cancel-btn')}\n onClick={(e) => {\n e.stopPropagation();\n (onCancel ?? onRemove)(preview.id);\n }}\n aria-label={ui.cancelUpload}\n >\n <X size={13} />\n <span>{ui.cancelUpload}</span>\n </button>\n )}\n </div>\n )}\n\n {isSuccess && (\n <div data-slot=\"tile-badge\" className={cls('iuk-tile__badge iuk-tile__badge--success')}>\n <CheckCircle2 size={13} />\n {reductionPercent > 0 && <span>-{reductionPercent}%</span>}\n </div>\n )}\n\n {!disabled && !isUploading && !hasError && actualBlurColor && (\n <div data-slot=\"tile-color-badge\" className={cls('iuk-tile__badge iuk-tile__badge--color')}>\n <span className={cls('iuk-tile__color-dot')} style={{ backgroundColor: actualBlurColor }} />\n <code>{actualBlurColor.toUpperCase()}</code>\n </div>\n )}\n\n {hasError && (\n <div\n data-slot=\"tile-error\"\n role=\"alert\"\n className={cls('iuk-tile__overlay iuk-tile__overlay--error')}\n >\n <XCircle size={22} />\n <p>{preview.error}</p>\n {!disabled && onRetry && (\n <button\n type=\"button\"\n data-slot=\"tile-retry\"\n className={cls('iuk-btn iuk-btn--secondary iuk-btn--sm iuk-tile__retry-btn')}\n onClick={(e) => {\n e.stopPropagation();\n onRetry(preview.id);\n }}\n aria-label={ui.retryUpload}\n >\n <span>{ui.retryUpload}</span>\n </button>\n )}\n </div>\n )}\n </div>\n\n <BlurVisualizationModal\n isOpen={showBlurModal}\n onClose={() => setShowBlurModal(false)}\n imageUrl={preview.url}\n blurDataUrl={actualBlurDataUrl}\n blurColor={actualBlurColor}\n detectedColor={preview.data?.blurColor}\n altText={preview.altText}\n originalSize={preview.originalSize}\n optimizedSize={preview.optimizedSize}\n locale={locale}\n translations={translations}\n renderImage={renderImage}\n unstyled={isUnstyled}\n onChangeColor={(hex) => onChangeColor?.(preview.id, hex)}\n onUseDetectedColor={\n onChangeColor && preview.data?.blurColor\n ? () => onChangeColor(preview.id, preview.data!.blurColor!)\n : undefined\n }\n onChangeAltText={(nextAlt) => onChangeAltText?.(preview.id, nextAlt)}\n />\n </div>\n );\n}\n\nexport default PreviewTile;\n","import { CheckIcon as Check, InfoIcon as Info, ZapIcon as Zap } from '../icons';\nimport type { KeyboardEvent } from 'react';\nimport type {\n QualityLevel,\n StandardPresetName,\n UploadLocale,\n} from '../../types';\nimport { QUALITY_PRESETS, STANDARD_PRESETS } from '../../types';\nimport { estimateOutputSize } from '../../utils/formatters';\nimport {\n normalizeUploadLocale,\n resolveTranslations,\n type UploadTranslations,\n} from '../i18n';\nimport { cx, resolveSlotClass } from '../utils/slotStyles';\n\nfunction formatBytesCompact(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;\n}\n\nexport interface QualitySelectorProps {\n value: QualityLevel;\n onChange: (level: QualityLevel) => void;\n preset?: string;\n recommendedLevel?: QualityLevel;\n recommendationNote?: { en: string; ar?: string };\n originalFileSize?: number;\n locale?: UploadLocale;\n translations?: Partial<UploadTranslations>;\n disabled?: boolean;\n unstyled?: boolean;\n}\n\nexport function QualitySelector({\n value,\n onChange,\n preset,\n recommendedLevel,\n recommendationNote,\n originalFileSize,\n locale,\n translations,\n disabled = false,\n unstyled = false,\n}: QualitySelectorProps) {\n const resolvedLocale = normalizeUploadLocale(locale);\n const isAr = resolvedLocale === 'ar';\n const ui = resolveTranslations(resolvedLocale, translations);\n const cls = (defaultClass: string) => resolveSlotClass(defaultClass, unstyled);\n\n const standardPreset = preset\n ? STANDARD_PRESETS[preset as StandardPresetName]\n : undefined;\n\n const recommended: QualityLevel =\n recommendedLevel || standardPreset?.recommendedQualityLevel || 'high';\n const note = recommendationNote || standardPreset?.recommendationNote;\n\n const selected = QUALITY_PRESETS[value];\n const levels = Object.keys(QUALITY_PRESETS) as QualityLevel[];\n const estimatedSize =\n originalFileSize !== undefined\n ? estimateOutputSize(originalFileSize, value)\n : null;\n const saving = Math.round((1 - selected.compressionRatio) * 100);\n\n const handleRadioGroupKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (disabled) return;\n const currentIndex = Math.max(0, levels.indexOf(value));\n let nextIndex = -1;\n\n if (event.key === 'ArrowRight' || event.key === 'ArrowDown') {\n const step = event.key === 'ArrowRight' && isAr ? -1 : 1;\n nextIndex = (currentIndex + step + levels.length) % levels.length;\n } else if (event.key === 'ArrowLeft' || event.key === 'ArrowUp') {\n const step = event.key === 'ArrowLeft' && isAr ? 1 : -1;\n nextIndex = (currentIndex + step + levels.length) % levels.length;\n } else if (event.key === 'Home') {\n nextIndex = 0;\n } else if (event.key === 'End') {\n nextIndex = levels.length - 1;\n }\n\n if (nextIndex >= 0) {\n event.preventDefault();\n const nextLevel = levels[nextIndex];\n onChange(nextLevel);\n const buttons = event.currentTarget.querySelectorAll<HTMLButtonElement>('[role=\"radio\"]');\n buttons[nextIndex]?.focus();\n }\n };\n\n return (\n <div\n data-slot=\"quality-root\"\n data-unstyled={unstyled || undefined}\n className={cls('iuk-quality')}\n dir={isAr ? 'rtl' : 'ltr'}\n >\n <div className={cls('iuk-quality__header')}>\n <span className={cls('iuk-quality__title')}>\n {ui.qualityTitle}\n </span>\n <span className={cls(`iuk-quality__pill iuk-quality__pill--${value}`)}>\n {isAr ? selected.labelAr : selected.label} · Q{selected.value}\n </span>\n </div>\n\n <div\n className={cls('iuk-quality__tabs')}\n role=\"radiogroup\"\n aria-label={ui.qualityLevelAria}\n onKeyDown={handleRadioGroupKeyDown}\n >\n {levels.map((level) => {\n const item = QUALITY_PRESETS[level];\n const isSelected = value === level;\n const isRecommended = level === recommended;\n return (\n <button\n key={level}\n type=\"button\"\n role=\"radio\"\n aria-checked={isSelected}\n tabIndex={disabled ? -1 : isSelected ? 0 : -1}\n disabled={disabled}\n onClick={() => !disabled && onChange(level)}\n className={cls(\n cx(\n 'iuk-quality__tab',\n isSelected && 'iuk-quality__tab--selected',\n isRecommended && !isSelected && 'iuk-quality__tab--recommended',\n disabled && 'iuk-quality__tab--disabled',\n ),\n )}\n >\n {isSelected && (\n <Check size={11} strokeWidth={3} aria-hidden=\"true\" />\n )}\n <span>{isAr ? item.labelAr : item.label}</span>\n {isRecommended && !isSelected && (\n <span className={cls('iuk-quality__star')} aria-hidden=\"true\">\n ★\n </span>\n )}\n </button>\n );\n })}\n </div>\n\n <div className={cls(`iuk-quality__detail iuk-quality__detail--${value}`)}>\n <p className={cls('iuk-quality__desc')}>\n {isAr ? selected.descriptionAr : selected.description}\n </p>\n <div className={cls('iuk-quality__meta')}>\n <span className={cls('iuk-quality__tag')}>Q{selected.value}</span>\n {estimatedSize !== null && (\n <>\n <span className={cls('iuk-quality__dot')} aria-hidden=\"true\" />\n <Zap size={11} aria-hidden=\"true\" />\n <span>~{formatBytesCompact(estimatedSize)}</span>\n <span className={cls('iuk-quality__dot')} aria-hidden=\"true\" />\n <span className={cls('iuk-quality__saving')}>\n {saving}% {ui.qualitySaved}\n </span>\n </>\n )}\n {value === recommended && (\n <span className={cls('iuk-quality__rec-badge')}>\n ⭐ {ui.qualityRecommended}\n </span>\n )}\n </div>\n </div>\n\n {note && (\n <div className={cls('iuk-quality__note')}>\n <Info size={12} aria-hidden=\"true\" className={cls('iuk-quality__note-icon')} />\n <span>{isAr ? note.ar || note.en : note.en}</span>\n </div>\n )}\n </div>\n );\n}\n\nexport default QualitySelector;\n","import {\n ChevronDownIcon as ChevronDown,\n ChevronUpIcon as ChevronUp,\n LoaderIcon as Loader2,\n} from '../icons';\nimport { useEffect, useRef, useState } from 'react';\nimport type { UploadLocale } from '../../types';\nimport { useImageUploadContext } from '../context';\nimport {\n formatUploadingCount,\n normalizeUploadLocale,\n resolveTranslations,\n type UploadTranslations,\n} from '../i18n';\nimport type { CustomImageRenderer, ImagePreview } from '../types';\nimport { cx, resolveSlotClass } from '../utils/slotStyles';\nimport { BlurImage } from './BlurImage';\n\nconst PROGRESS_PANEL_DISMISS_DELAY_MS = 2500;\n\nexport interface UploadItem {\n id: string;\n url: string;\n fileName?: string;\n message?: string;\n progress?: number;\n}\n\nexport function useRetainedProgressItems(\n uploadingPreviews: ImagePreview[],\n previews: ImagePreview[],\n): UploadItem[] {\n const [retainedItems, setRetainedItems] = useState<UploadItem[] | null>(null);\n const activeBatchRef = useRef<Map<string, UploadItem>>(new Map());\n const dismissTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const prevUploadingCountRef = useRef(0);\n const isUploading = uploadingPreviews.length > 0;\n\n useEffect(() => {\n if (isUploading) {\n if (dismissTimerRef.current) {\n clearTimeout(dismissTimerRef.current);\n dismissTimerRef.current = null;\n activeBatchRef.current.clear();\n }\n setRetainedItems(null);\n for (const p of uploadingPreviews) {\n activeBatchRef.current.set(p.id, {\n id: p.id,\n url: p.url,\n fileName: p.fileName || p.file?.name,\n message: p.uploadMessage || undefined,\n progress: p.progress,\n });\n }\n } else if (prevUploadingCountRef.current > 0 && activeBatchRef.current.size > 0) {\n const completed: UploadItem[] = Array.from(activeBatchRef.current.values()).map((it) => {\n const found = previews.find((p) => p.id === it.id);\n return {\n ...it,\n progress: found?.progress ?? 100,\n message: found?.error ? found.error : (found?.uploadMessage || undefined),\n };\n });\n setRetainedItems(completed);\n dismissTimerRef.current = setTimeout(() => {\n setRetainedItems(null);\n activeBatchRef.current.clear();\n dismissTimerRef.current = null;\n }, PROGRESS_PANEL_DISMISS_DELAY_MS);\n }\n prevUploadingCountRef.current = uploadingPreviews.length;\n }, [isUploading, uploadingPreviews, previews]);\n\n useEffect(() => () => {\n if (dismissTimerRef.current) clearTimeout(dismissTimerRef.current);\n }, []);\n\n return isUploading\n ? uploadingPreviews.map((p) => ({\n id: p.id,\n url: p.url,\n fileName: p.fileName || p.file?.name,\n message: p.uploadMessage || undefined,\n progress: p.progress,\n }))\n : (retainedItems ?? []);\n}\n\nexport interface UploadProgressPanelProps {\n items: UploadItem[];\n completedCount: number;\n totalCount: number;\n locale?: UploadLocale;\n translations?: Partial<UploadTranslations>;\n renderImage?: CustomImageRenderer;\n unstyled?: boolean;\n}\n\nexport function UploadProgressPanel({\n items,\n completedCount,\n totalCount,\n locale: propLocale,\n translations,\n renderImage,\n unstyled: propUnstyled,\n}: UploadProgressPanelProps) {\n const ctx = useImageUploadContext();\n const isUnstyled = propUnstyled ?? ctx.unstyled;\n const locale = normalizeUploadLocale(propLocale || ctx.locale);\n const effectiveOverrides = translations || ctx.translations;\n const ui = resolveTranslations(locale, effectiveOverrides);\n const [isMinimized, setIsMinimized] = useState(false);\n const uploadingCount = items.length;\n const cls = (defaultClass: string) => resolveSlotClass(defaultClass, isUnstyled);\n\n if (uploadingCount === 0) return null;\n\n return (\n <div\n data-upload-progress-dock\n data-slot=\"progress-dock\"\n data-unstyled={isUnstyled || undefined}\n dir={locale === 'ar' ? 'rtl' : 'ltr'}\n className={cls(\n cx('iuk-progress-dock', isMinimized && 'iuk-progress-dock--collapsed'),\n )}\n >\n <div\n className={cls(\n cx('iuk-progress-panel', isMinimized && 'iuk-progress-panel--minimized'),\n )}\n >\n <button\n type=\"button\"\n className={cls('iuk-progress-panel__header')}\n aria-expanded={!isMinimized}\n onClick={() => setIsMinimized((prev) => !prev)}\n >\n <span className={cls('iuk-progress-panel__title')}>\n <Loader2 size={16} className={cls('iuk-spin')} />\n <span>\n {formatUploadingCount(ui, uploadingCount, locale, effectiveOverrides)}\n </span>\n {totalCount > 0 && (\n <span className={cls('iuk-progress-panel__count')}>\n ({completedCount}/{totalCount})\n </span>\n )}\n </span>\n {isMinimized ? <ChevronUp size={18} /> : <ChevronDown size={18} />}\n </button>\n\n {!isMinimized && (\n <div className={cls('iuk-progress-panel__body')}>\n {items.map((item) => (\n <div key={item.id} className={cls('iuk-progress-item')}>\n <div className={cls('iuk-progress-item__thumb')}>\n <BlurImage\n src={item.url}\n alt={ui.uploadingAlt}\n objectFit=\"cover\"\n renderImage={renderImage}\n />\n </div>\n <div className={cls('iuk-progress-item__info')}>\n <div className={cls('iuk-progress-item__name')}>\n {item.fileName || ui.image}\n </div>\n <div className={cls('iuk-progress-item__status')}>\n {item.message || ui.processing}\n </div>\n {item.progress !== undefined && item.progress > 0 && (\n <div\n role=\"progressbar\"\n aria-valuenow={Math.round(item.progress)}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={item.fileName || ui.uploading}\n className={cls('iuk-progress-bar')}\n >\n <div\n className={cls('iuk-progress-bar__fill')}\n style={{ width: `${item.progress}%` }}\n />\n </div>\n )}\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nexport default UploadProgressPanel;\n","import {\n type ChangeEvent, type ForwardedRef, forwardRef, type HTMLAttributes,\n type ReactElement, type Ref, useId, useImperativeHandle, useRef,\n} from 'react';\nimport type { UploadPresetName } from '../../types';\nimport { useImageUploadContext } from '../context';\nimport { useClipboardPaste } from '../hooks/useClipboardPaste';\nimport { useDragAndDrop } from '../hooks/useDragAndDrop';\nimport { useSingleImageState } from '../hooks/useSingleImageState';\nimport type { SingleUploadSlot } from '../styling';\nimport type { ImageUploadHandle, SingleImageUploadProps } from '../types';\nimport {\n HIDDEN_INPUT_STYLE, resolveSlotClass, resolveSlotStyle, resolveUploadDataState,\n} from '../utils/slotStyles';\nimport { AltTextModal } from './AltTextModal';\nimport { BlurVisualizationModal } from './BlurVisualizationModal';\nimport { PreviewTile } from './PreviewTile';\nimport { QualitySelector } from './QualitySelector';\nimport {\n resolveSingleDropzoneSlot, SingleDropzoneEmptyPrompt, SingleStatusFooter,\n} from './SingleDropzoneContent';\n\nfunction SingleImageUploadInner<TPreset extends string = UploadPresetName>(\n props: SingleImageUploadProps<TPreset>,\n ref: ForwardedRef<ImageUploadHandle>,\n) {\n const {\n preset, translations, renderImage, label, error, helperText, className, style,\n accept = 'image/jpeg,image/png,image/webp,image/avif,image/svg+xml',\n disabled = false, required = false, blurType = 'card',\n showProgress = false, showQualitySelector = true,\n recommendedQuality, qualityNote, isOpen,\n capture, enablePaste = true, pasteTarget = 'dropzone', name, onBlur,\n classNames: cCls, styles: cSty, renderDropzone, renderPreview,\n } = props;\n\n const ctx = useImageUploadContext();\n const isUnstyled = props.unstyled ?? ctx.unstyled;\n const pCls = ctx.singleClassNames;\n const pSty = ctx.singleStyles;\n\n const slotClass = (slot: SingleUploadSlot, defaultClass?: string) =>\n resolveSlotClass(defaultClass, isUnstyled, pCls?.[slot], cCls?.[slot]);\n const slotStyle = (slot: SingleUploadSlot) =>\n resolveSlotStyle(pSty?.[slot], cSty?.[slot]);\n\n const state = useSingleImageState(props);\n const { isDragging, dragHandlers } = useDragAndDrop({ disabled, onDrop: state.handleFileSelect });\n const { onPaste } = useClipboardPaste({\n enabled: enablePaste, pasteTarget, disabled, multiple: false,\n onPasteFiles: (files) => { void state.handleFileSelect(files); },\n });\n\n const dropzoneRef = useRef<HTMLDivElement>(null);\n const labelId = useId();\n const inputId = useId();\n const statusTextId = useId();\n\n const openFileDialog = () => { if (!disabled) state.fileInputRef.current?.click(); };\n\n useImperativeHandle(ref, () => ({\n focus: () => { dropzoneRef.current?.focus(); },\n open: openFileDialog,\n clear: () => state.handleRemoveTile(),\n }));\n\n const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {\n const files = event.target.files;\n if (files && files.length > 0) void state.handleFileSelect(files);\n event.target.value = '';\n };\n\n const displayError = error || state.validationError;\n const hasPreview = Boolean(state.preview);\n const hasError = Boolean(displayError);\n const hasLabel = Boolean(label || state.ui.uploadImage);\n const hasStatusText = Boolean(helperText || displayError);\n const visualState = resolveUploadDataState({\n disabled, hasError, isUploading: state.isUploading, isDragging, hasContent: hasPreview,\n });\n\n const dropzoneProps: HTMLAttributes<HTMLElement> = hasPreview\n ? { ...dragHandlers, onPaste, 'aria-disabled': disabled || undefined }\n : {\n ...dragHandlers, onPaste,\n onClick: () => { if (!disabled) openFileDialog(); },\n onKeyDown: (event) => {\n if (!disabled && (event.key === 'Enter' || event.key === ' ')) {\n event.preventDefault();\n openFileDialog();\n }\n },\n role: 'button', tabIndex: disabled ? -1 : 0,\n 'aria-label': state.ui.uploadImageAria,\n 'aria-labelledby': hasLabel ? labelId : undefined,\n 'aria-required': required || undefined,\n 'aria-invalid': hasError || undefined,\n 'aria-describedby': hasStatusText ? statusTextId : undefined,\n 'aria-disabled': disabled || undefined,\n };\n\n const slotStylingProps = {\n unstyled: isUnstyled, providerClassNames: pCls, classNames: cCls, providerStyles: pSty, styles: cSty,\n };\n const dropzoneSlot = resolveSingleDropzoneSlot(\n { isDragging, hasPreview, disabled, hasError }, slotStylingProps,\n );\n\n return (\n <div\n data-slot=\"single-root\" data-state={visualState} data-unstyled={isUnstyled || undefined}\n className={resolveSlotClass('iuk-single', isUnstyled, pCls?.root, cCls?.root, className)}\n style={resolveSlotStyle(pSty?.root, cSty?.root, style)}\n dir={state.locale === 'ar' ? 'rtl' : 'ltr'}\n onBlur={onBlur ? (e) => { if (!e.currentTarget.contains(e.relatedTarget as Node | null)) onBlur(); } : undefined}\n >\n <div role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" style={HIDDEN_INPUT_STYLE}>\n {state.liveAnnouncement}\n </div>\n\n {name && (\n <input type=\"hidden\" name={name} value={state.serializedFormValue} required={required} data-slot=\"form-input\" />\n )}\n\n {hasLabel && (\n <label id={labelId} htmlFor={inputId} data-slot=\"label\" className={slotClass('label', 'iuk-label')} style={slotStyle('label')}>\n <span>{label || state.ui.uploadImage}</span>\n {required && <span className={resolveSlotClass('iuk-required', isUnstyled)}>*</span>}\n </label>\n )}\n\n {showQualitySelector && (\n <div data-slot=\"quality-selector\" className={slotClass('qualitySelector')} style={slotStyle('qualitySelector')}>\n <QualitySelector\n value={state.qualityLevel} onChange={state.setQualityLevel} preset={preset}\n recommendedLevel={recommendedQuality} recommendationNote={qualityNote}\n originalFileSize={state.selectedFile?.size} locale={state.locale}\n disabled={disabled || state.isUploading} unstyled={isUnstyled}\n />\n </div>\n )}\n\n <input\n id={inputId} ref={state.fileInputRef} type=\"file\" accept={accept} capture={capture}\n onChange={handleInputChange}\n className={resolveSlotClass('iuk-hidden-input', isUnstyled)}\n style={isUnstyled ? HIDDEN_INPUT_STYLE : undefined}\n disabled={disabled} aria-label={state.ui.fileInputAria}\n aria-invalid={hasError || undefined}\n aria-describedby={hasStatusText ? statusTextId : undefined}\n />\n\n {!state.preview && renderDropzone ? (\n renderDropzone({\n state: visualState, isDragging, isUploading: state.isUploading,\n progress: state.progress, uploadMessage: state.uploadMessage,\n maxSizeMB: state.maxSizeMB, disabled, error: displayError || undefined,\n qualityLevel: state.qualityLevel, setQualityLevel: state.setQualityLevel,\n openFileDialog, dropzoneProps, locale: state.locale, ui: state.ui,\n })\n ) : (\n <div\n ref={dropzoneRef} data-slot=\"dropzone\" data-state={visualState}\n data-dragging={isDragging || undefined} data-uploading={state.isUploading || undefined}\n data-disabled={disabled || undefined} data-error={hasError || undefined}\n className={dropzoneSlot.className} style={dropzoneSlot.style} {...dropzoneProps}\n >\n {state.preview ? (\n <div\n data-slot=\"preview-wrap\" className={slotClass('previewWrap', 'iuk-single__preview-wrap')}\n style={slotStyle('previewWrap')} onClick={(event) => event.stopPropagation()}\n >\n {renderPreview ? (\n renderPreview({\n previewUrl: state.preview, uploadedData: state.uploadedData, altText: state.altText,\n blurColor: state.uploadedData?.blurColor ?? state.blurColor,\n blurDataUrl: state.blurDataUrlState || state.currentImageData?.blurDataUrl || '',\n isUploading: state.isUploading, progress: state.progress,\n uploadMessage: state.uploadMessage, sizeInfo: state.sizeInfo, disabled,\n openFileDialog, remove: () => state.handleRemoveTile(),\n cancel: () => state.handleCancelUpload(),\n openAltTextModal: () => state.setEditingAltText(true),\n openBlurInspector: () => state.setIsBlurModalOpen(true),\n download: state.handleDownload, locale: state.locale, ui: state.ui,\n })\n ) : (\n <PreviewTile\n preview={{\n id: 'single', url: state.preview, altText: state.altText,\n isUploading: state.isUploading, progress: state.progress,\n uploadMessage: state.uploadMessage || null,\n originalSize: state.sizeInfo?.original,\n optimizedSize: state.sizeInfo?.optimized ?? null,\n data: state.uploadedData ?? undefined,\n blurColor: state.uploadedData?.blurColor ?? state.blurColor,\n }}\n onRemove={() => state.handleRemoveTile()} onCancel={() => state.handleCancelUpload()}\n disabled={disabled} blurType={blurType} showCheckbox={false}\n onEditAltText={() => state.setEditingAltText(true)}\n onAdjustColor={() => state.setIsBlurModalOpen(true)}\n locale={state.locale} translations={translations} renderImage={renderImage}\n unstyled={isUnstyled} className={slotClass('tile')} style={slotStyle('tile')}\n />\n )}\n </div>\n ) : (\n <SingleDropzoneEmptyPrompt\n isUploading={state.isUploading} uploadMessage={state.uploadMessage}\n showProgress={showProgress} progress={state.progress}\n maxSizeMB={state.maxSizeMB} enablePaste={enablePaste} ui={state.ui} {...slotStylingProps}\n />\n )}\n </div>\n )}\n\n <SingleStatusFooter\n showMissingAltWarning={state.showMissingAltWarning}\n hasPreview={hasPreview} hasAltText={Boolean(state.altText?.trim())}\n uploadMessage={state.uploadMessage} isUploading={state.isUploading}\n sizeInfo={state.sizeInfo} canDownload={state.canDownload}\n onDownload={() => void state.handleDownload()}\n helperText={helperText} displayError={displayError} statusTextId={statusTextId}\n isOpen={isOpen} requireAltText={state.requireAltText}\n disabled={disabled} onSave={state.handleSaveImage}\n ui={state.ui} {...slotStylingProps}\n />\n\n {state.editingAltText && state.preview && (\n <AltTextModal\n imageUrl={state.preview} initialAltText={state.altText}\n onSave={state.handleAltTextSave} onClose={() => state.setEditingAltText(false)}\n locale={state.locale} translations={translations} renderImage={renderImage}\n />\n )}\n\n {state.preview && (\n <BlurVisualizationModal\n isOpen={state.isBlurModalOpen} onClose={() => state.setIsBlurModalOpen(false)}\n imageUrl={state.preview}\n blurDataUrl={state.blurDataUrlState || state.currentImageData?.blurDataUrl}\n blurColor={state.blurColor} altText={state.altText}\n originalSize={state.sizeInfo?.original ?? state.currentImageData?.originalSize}\n optimizedSize={state.sizeInfo?.optimized ?? state.currentImageData?.size ?? null}\n detectedColor={state.detectedBlurColor}\n onChangeColor={(hex) => state.applyBlurColor(hex)}\n onUseDetectedColor={state.handleResetColor}\n onChangeAltText={(nextAlt) => state.handleAltTextSave(nextAlt)}\n locale={state.locale} translations={translations} renderImage={renderImage}\n />\n )}\n </div>\n );\n}\n\nexport const SingleImageUpload = forwardRef(SingleImageUploadInner) as <\n TPreset extends string = UploadPresetName,\n>(\n props: SingleImageUploadProps<TPreset> & { ref?: Ref<ImageUploadHandle> },\n) => ReactElement | null;\n\nexport default SingleImageUpload;\n","import {\n AlertTriangleIcon as AlertTriangle,\n DownloadIcon as Download,\n ImagePlusIcon as ImagePlus,\n SaveIcon as Save,\n UploadIcon as Upload,\n} from '../icons';\nimport type { CSSProperties } from 'react';\nimport type { UploadTranslations } from '../i18n';\nimport type {\n SingleUploadClassNames,\n SingleUploadSlot,\n SingleUploadStyles,\n} from '../styling';\nimport { cx, resolveSlotClass, resolveSlotStyle } from '../utils/slotStyles';\nimport { SaveButton } from './SaveButton';\n\nfunction formatCompactBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;\n}\n\nexport interface SingleSlotStylingProps {\n unstyled?: boolean;\n providerClassNames?: SingleUploadClassNames;\n classNames?: SingleUploadClassNames;\n providerStyles?: SingleUploadStyles;\n styles?: SingleUploadStyles;\n}\n\nexport function resolveSingleDropzoneSlot(\n flags: {\n isDragging: boolean;\n hasPreview: boolean;\n disabled: boolean;\n hasError: boolean;\n },\n styling: SingleSlotStylingProps,\n): { className?: string; style?: CSSProperties } {\n const { isDragging, hasPreview, disabled, hasError } = flags;\n const { unstyled, providerClassNames: pCls, classNames: cCls, providerStyles: pSty, styles: cSty } = styling;\n return {\n className: resolveSlotClass(\n cx(\n 'iuk-dropzone',\n isDragging && 'iuk-dropzone--dragging',\n hasPreview && 'iuk-dropzone--has-image',\n disabled && 'iuk-dropzone--disabled',\n hasError && 'iuk-dropzone--error',\n ),\n unstyled,\n pCls?.dropzone, cCls?.dropzone,\n isDragging && pCls?.dropzoneDragging, isDragging && cCls?.dropzoneDragging,\n hasPreview && pCls?.dropzoneHasImage, hasPreview && cCls?.dropzoneHasImage,\n disabled && pCls?.dropzoneDisabled, disabled && cCls?.dropzoneDisabled,\n hasError && pCls?.dropzoneError, hasError && cCls?.dropzoneError,\n ),\n style: resolveSlotStyle(\n pSty?.dropzone, cSty?.dropzone,\n isDragging ? pSty?.dropzoneDragging : undefined, isDragging ? cSty?.dropzoneDragging : undefined,\n hasPreview ? pSty?.dropzoneHasImage : undefined, hasPreview ? cSty?.dropzoneHasImage : undefined,\n disabled ? pSty?.dropzoneDisabled : undefined, disabled ? cSty?.dropzoneDisabled : undefined,\n hasError ? pSty?.dropzoneError : undefined, hasError ? cSty?.dropzoneError : undefined,\n ),\n };\n}\n\nexport interface SingleDropzoneEmptyPromptProps extends SingleSlotStylingProps {\n isUploading: boolean;\n uploadMessage: string;\n showProgress: boolean;\n progress: number;\n maxSizeMB: number;\n enablePaste?: boolean;\n ui: UploadTranslations;\n}\n\nexport function SingleDropzoneEmptyPrompt({\n isUploading, uploadMessage, showProgress, progress, maxSizeMB, enablePaste = true, ui,\n unstyled, providerClassNames, classNames, providerStyles, styles,\n}: SingleDropzoneEmptyPromptProps) {\n const slotClass = (slot: SingleUploadSlot, defaultClass?: string) =>\n resolveSlotClass(defaultClass, unstyled, providerClassNames?.[slot], classNames?.[slot]);\n const slotStyle = (slot: SingleUploadSlot) =>\n resolveSlotStyle(providerStyles?.[slot], styles?.[slot]);\n\n return (\n <div\n data-slot=\"dropzone-prompt\"\n className={slotClass('dropzonePrompt', 'iuk-dropzone__prompt')}\n style={slotStyle('dropzonePrompt')}\n >\n <div\n data-slot=\"dropzone-icon\"\n className={slotClass('dropzoneIcon', 'iuk-dropzone__icon')}\n style={slotStyle('dropzoneIcon')}\n >\n {isUploading ? (\n <div className={resolveSlotClass('iuk-spinner', unstyled)} />\n ) : (\n <ImagePlus size={36} strokeWidth={1.5} />\n )}\n </div>\n <p\n data-slot=\"dropzone-text\"\n className={slotClass('dropzoneText', 'iuk-dropzone__text')}\n style={slotStyle('dropzoneText')}\n >\n {isUploading ? uploadMessage || `${ui.uploading}...` : ui.dragDropOrClickToUpload}\n </p>\n {isUploading && showProgress && progress > 0 && (\n <p\n data-slot=\"dropzone-progress\"\n role=\"progressbar\"\n aria-valuenow={Math.round(progress)}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={ui.uploading}\n className={slotClass('dropzoneProgress', 'iuk-dropzone__progress')}\n style={slotStyle('dropzoneProgress')}\n >\n {progress}%\n </p>\n )}\n {!isUploading && (\n <>\n <p\n data-slot=\"dropzone-hint\"\n className={slotClass('dropzoneHint', 'iuk-dropzone__hint')}\n style={slotStyle('dropzoneHint')}\n >\n {ui.upToSizeMB.replace('{size}', String(maxSizeMB))}\n {enablePaste ? ` • ${ui.pasteHint}` : ''}\n </p>\n <span\n data-slot=\"browse-button\"\n className={slotClass('browseButton', 'iuk-btn iuk-btn--secondary')}\n style={slotStyle('browseButton')}\n >\n <Upload size={15} />\n <span>{ui.browseFiles}</span>\n </span>\n </>\n )}\n </div>\n );\n}\n\nexport interface SingleStatusFooterProps extends SingleSlotStylingProps {\n showMissingAltWarning: boolean;\n hasPreview: boolean;\n hasAltText: boolean;\n uploadMessage: string;\n isUploading: boolean;\n sizeInfo: { original: number; optimized: number } | null;\n canDownload: boolean;\n onDownload: () => void;\n helperText?: string;\n displayError?: string;\n statusTextId?: string;\n isOpen?: boolean;\n requireAltText?: boolean;\n disabled?: boolean;\n onSave?: () => void;\n ui: UploadTranslations;\n}\n\nexport function SingleStatusFooter({\n showMissingAltWarning, hasPreview, hasAltText, uploadMessage, isUploading,\n sizeInfo, canDownload, onDownload, helperText, displayError, statusTextId,\n isOpen, requireAltText, disabled, onSave, ui,\n unstyled, providerClassNames, classNames, providerStyles, styles,\n}: SingleStatusFooterProps) {\n const slotClass = (slot: SingleUploadSlot, defaultClass?: string) =>\n resolveSlotClass(defaultClass, unstyled, providerClassNames?.[slot], classNames?.[slot]);\n const slotStyle = (slot: SingleUploadSlot) =>\n resolveSlotStyle(providerStyles?.[slot], styles?.[slot]);\n\n return (\n <>\n {showMissingAltWarning && hasPreview && !hasAltText && (\n <div\n data-slot=\"alert\"\n role=\"alert\"\n className={slotClass('alert', 'iuk-alert iuk-alert--warning')}\n style={slotStyle('alert')}\n >\n <AlertTriangle size={16} />\n <span>{ui.addAltBeforeSaving}</span>\n </div>\n )}\n\n {uploadMessage && !isUploading && sizeInfo && (\n <div\n data-slot=\"alert\"\n role=\"status\"\n className={slotClass('alert', 'iuk-alert iuk-alert--success')}\n style={slotStyle('alert')}\n >\n <span>{uploadMessage}</span>\n </div>\n )}\n\n {hasPreview && canDownload && (\n <button\n type=\"button\"\n data-slot=\"download-button\"\n className={slotClass('downloadButton', 'iuk-btn iuk-btn--secondary iuk-single__download')}\n style={slotStyle('downloadButton')}\n onClick={onDownload}\n disabled={isUploading}\n aria-label={ui.downloadImage}\n >\n <Download size={15} aria-hidden=\"true\" />\n <span>{ui.downloadImage}</span>\n {sizeInfo && (\n <span className={resolveSlotClass('iuk-badge', unstyled)}>\n {formatCompactBytes(sizeInfo.optimized)}\n </span>\n )}\n </button>\n )}\n\n {(helperText || displayError) && (\n <p\n id={statusTextId}\n role={displayError ? 'alert' : undefined}\n data-slot={displayError ? 'error-text' : 'helper-text'}\n className={resolveSlotClass(\n cx('iuk-helper-text', Boolean(displayError) && 'iuk-helper-text--error'),\n unstyled,\n providerClassNames?.helperText, classNames?.helperText,\n Boolean(displayError) && providerClassNames?.errorText,\n Boolean(displayError) && classNames?.errorText,\n )}\n style={resolveSlotStyle(\n providerStyles?.helperText, styles?.helperText,\n displayError ? providerStyles?.errorText : undefined,\n displayError ? styles?.errorText : undefined,\n )}\n >\n {displayError || helperText}\n </p>\n )}\n\n {isOpen && hasPreview && onSave && (\n <div\n data-slot=\"commit-bar\"\n className={slotClass('commitBar', 'iuk-commit-bar')}\n style={slotStyle('commitBar')}\n >\n {requireAltText && !hasAltText && (\n <div className={resolveSlotClass('iuk-badge iuk-badge--warning', unstyled)}>\n <AlertTriangle size={13} />\n <span>{ui.missingDescription}</span>\n </div>\n )}\n <SaveButton\n unstyled={unstyled}\n className={slotClass('saveButton')}\n style={slotStyle('saveButton')}\n onClick={onSave}\n disabled={isUploading || disabled || Boolean(requireAltText && !hasAltText)}\n icon={<Save size={16} />}\n >\n {ui.saveImage}\n </SaveButton>\n </div>\n )}\n </>\n );\n}\n"]}
|