img-upload-kit 2.0.1 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/CHANGELOG.md +89 -89
  2. package/MIGRATION.md +192 -192
  3. package/README.md +243 -243
  4. package/dist/bin.js +1 -1
  5. package/dist/bin.js.map +1 -1
  6. package/dist/blur.cjs +3 -3
  7. package/dist/blur.cjs.map +1 -1
  8. package/dist/blur.js +2 -2
  9. package/dist/{chunk-XKQMCY5Z.cjs → chunk-2OVNXHTN.cjs} +1 -1
  10. package/dist/chunk-2OVNXHTN.cjs.map +1 -0
  11. package/dist/{chunk-FP5YIWG5.cjs → chunk-3ICG2SLL.cjs} +1 -1
  12. package/dist/chunk-3ICG2SLL.cjs.map +1 -0
  13. package/dist/{chunk-J6A44Y3W.js → chunk-4ASFG3KB.js} +1 -1
  14. package/dist/chunk-4ASFG3KB.js.map +1 -0
  15. package/dist/{chunk-IDLLCVGB.js → chunk-AI3JJLSA.js} +3 -3
  16. package/dist/chunk-AI3JJLSA.js.map +1 -0
  17. package/dist/{chunk-MHGQEBPW.js → chunk-CV23O4YU.js} +1 -1
  18. package/dist/chunk-CV23O4YU.js.map +1 -0
  19. package/dist/{chunk-25GYKQ6J.js → chunk-G7LLSKBV.js} +1 -1
  20. package/dist/chunk-G7LLSKBV.js.map +1 -0
  21. package/dist/{chunk-EWVIL57J.js → chunk-IB3TEDLR.js} +1 -1
  22. package/dist/chunk-IB3TEDLR.js.map +1 -0
  23. package/dist/{chunk-DFCSN3X7.cjs → chunk-KJVYWKIG.cjs} +1 -1
  24. package/dist/chunk-KJVYWKIG.cjs.map +1 -0
  25. package/dist/{chunk-34L4TEE3.cjs → chunk-NEDBIIE3.cjs} +1 -1
  26. package/dist/chunk-NEDBIIE3.cjs.map +1 -0
  27. package/dist/chunk-QHU7FUO4.cjs.map +1 -1
  28. package/dist/{chunk-VYVZVUNI.js → chunk-QQHZJKNA.js} +1 -1
  29. package/dist/chunk-QQHZJKNA.js.map +1 -0
  30. package/dist/{chunk-HILELQGS.js → chunk-TT5C7K3Q.js} +1 -1
  31. package/dist/chunk-TT5C7K3Q.js.map +1 -0
  32. package/dist/{chunk-TA5Y64JM.cjs → chunk-U2TWTEBY.cjs} +24 -24
  33. package/dist/chunk-U2TWTEBY.cjs.map +1 -0
  34. package/dist/{chunk-MBQJ6NVJ.cjs → chunk-WISG74VL.cjs} +1 -1
  35. package/dist/chunk-WISG74VL.cjs.map +1 -0
  36. package/dist/{chunk-LOSVFO56.cjs → chunk-YRXXQUDE.cjs} +1 -1
  37. package/dist/chunk-YRXXQUDE.cjs.map +1 -0
  38. package/dist/cli.cjs +1 -1
  39. package/dist/cli.cjs.map +1 -1
  40. package/dist/cli.js +1 -1
  41. package/dist/cli.js.map +1 -1
  42. package/dist/headless.cjs +4 -4
  43. package/dist/headless.cjs.map +1 -1
  44. package/dist/headless.js +3 -3
  45. package/dist/index.cjs +5 -5
  46. package/dist/index.cjs.map +1 -1
  47. package/dist/index.js +4 -4
  48. package/dist/react.cjs +138 -138
  49. package/dist/react.cjs.map +1 -1
  50. package/dist/react.js +5 -5
  51. package/dist/react.js.map +1 -1
  52. package/dist/server-handler.cjs +2 -2
  53. package/dist/server-handler.cjs.map +1 -1
  54. package/dist/server-handler.js +1 -1
  55. package/dist/server.cjs +30 -30
  56. package/dist/server.cjs.map +1 -1
  57. package/dist/server.js +2 -2
  58. package/dist/server.js.map +1 -1
  59. package/dist/storage.cjs +9 -9
  60. package/dist/storage.cjs.map +1 -1
  61. package/dist/storage.js +1 -1
  62. package/dist/storage.js.map +1 -1
  63. package/dist/styles/animated-image.css +112 -112
  64. package/dist/styles/tokens.css +123 -123
  65. package/dist/styles.css +235 -235
  66. package/package.json +1 -1
  67. package/dist/chunk-25GYKQ6J.js.map +0 -1
  68. package/dist/chunk-34L4TEE3.cjs.map +0 -1
  69. package/dist/chunk-DFCSN3X7.cjs.map +0 -1
  70. package/dist/chunk-EWVIL57J.js.map +0 -1
  71. package/dist/chunk-FP5YIWG5.cjs.map +0 -1
  72. package/dist/chunk-HILELQGS.js.map +0 -1
  73. package/dist/chunk-IDLLCVGB.js.map +0 -1
  74. package/dist/chunk-J6A44Y3W.js.map +0 -1
  75. package/dist/chunk-LOSVFO56.cjs.map +0 -1
  76. package/dist/chunk-MBQJ6NVJ.cjs.map +0 -1
  77. package/dist/chunk-MHGQEBPW.js.map +0 -1
  78. package/dist/chunk-TA5Y64JM.cjs.map +0 -1
  79. package/dist/chunk-VYVZVUNI.js.map +0 -1
  80. package/dist/chunk-XKQMCY5Z.cjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/blur/lruCache.ts","../src/blur/pathMapper.ts","../src/blur/placeholders.ts","../src/blur/blurService.ts"],"sourcesContent":["export class LRUCache<K, V> {\n private readonly maxSize: number;\n private readonly cache: Map<K, V>;\n\n constructor(maxSize: number = 500) {\n this.maxSize = Math.max(1, maxSize);\n this.cache = new Map();\n }\n\n get(key: K): V | undefined {\n if (!this.cache.has(key)) return undefined;\n\n const value = this.cache.get(key)!;\n this.cache.delete(key);\n this.cache.set(key, value);\n return value;\n }\n\n set(key: K, value: V): void {\n if (this.cache.has(key)) {\n this.cache.delete(key);\n }\n\n if (this.cache.size >= this.maxSize) {\n const firstKey = this.cache.keys().next().value;\n if (firstKey !== undefined) {\n this.cache.delete(firstKey);\n }\n }\n\n this.cache.set(key, value);\n }\n\n has(key: K): boolean {\n return this.cache.has(key);\n }\n\n clear(): void {\n this.cache.clear();\n }\n\n get size(): number {\n return this.cache.size;\n }\n}\n","export const DEFAULT_CDN_PATTERNS: RegExp[] = [\n /^https?:\\/\\/[^/]+\\.supabase\\.co\\/storage\\/v1\\/object\\/public\\/([^/]+)\\/(.+)$/,\n /^https?:\\/\\/[^/]+\\.r2\\.dev\\/(.+)$/,\n /^https?:\\/\\/[^/]+\\.amazonaws\\.com\\/(.+)$/,\n /^https?:\\/\\/[^/]+\\.cloudflare\\.com\\/(.+)$/,\n /^https?:\\/\\/cdn\\.[^/]+\\/(.+)$/,\n];\n\nexport interface NormalizePathOptions {\n cdnPatterns?: RegExp[];\n stripPrefixes?: string[];\n}\n\nexport interface PathInfo {\n normalizedPath: string;\n folder?: string;\n filename?: string;\n extension?: string;\n isExternal: boolean;\n originalPath: string;\n}\n\n/**\n * Project-agnostic image URL / path normalizer.\n * Strips query parameters, leading `/public/`, relative `./`, and common CDN prefixes\n * so manifest keys match consistently across local and CDN environments.\n */\nexport function normalizeImagePath(\n imageSrc: string,\n options: NormalizePathOptions = {},\n): PathInfo {\n const originalPath = imageSrc;\n let normalizedPath = imageSrc;\n let isExternal = false;\n\n try {\n if (imageSrc.startsWith('data:') || imageSrc.startsWith('blob:')) {\n return {\n normalizedPath: imageSrc,\n isExternal: false,\n originalPath,\n };\n }\n\n const patterns = options.cdnPatterns || DEFAULT_CDN_PATTERNS;\n\n if (imageSrc.startsWith('http://') || imageSrc.startsWith('https://')) {\n const url = new URL(imageSrc);\n isExternal = true;\n const cleanUrlNoQuery = `${url.origin}${url.pathname}`;\n\n for (const pattern of patterns) {\n const match = cleanUrlNoQuery.match(pattern);\n if (match) {\n const groups = match.slice(1).filter(Boolean);\n const pathPart = groups.join('/');\n normalizedPath = '/' + pathPart.replace(/^\\/+/, '');\n break;\n }\n }\n\n if (normalizedPath === imageSrc) {\n normalizedPath = url.pathname;\n }\n } else {\n normalizedPath = normalizedPath.split('?')[0].split('#')[0];\n }\n\n normalizedPath = normalizedPath.replace(/\\\\/g, '/').replace(/^\\.\\.?\\//g, '');\n\n if (!normalizedPath.startsWith('/')) {\n normalizedPath = '/' + normalizedPath;\n }\n\n const prefixesToStrip = options.stripPrefixes || ['/public/'];\n for (const prefix of prefixesToStrip) {\n if (normalizedPath.startsWith(prefix)) {\n normalizedPath = '/' + normalizedPath.slice(prefix.length).replace(/^\\/+/, '');\n }\n }\n\n const segments = normalizedPath.split('/').filter(Boolean);\n const filename = segments[segments.length - 1];\n const folder =\n segments.length > 1 ? segments.slice(0, -1).join('/') : undefined;\n const dotIdx = filename ? filename.lastIndexOf('.') : -1;\n const extension =\n filename && dotIdx > 0 ? filename.slice(dotIdx + 1).toLowerCase() : undefined;\n\n return {\n normalizedPath,\n folder,\n filename,\n extension,\n isExternal,\n originalPath,\n };\n } catch {\n return {\n normalizedPath: imageSrc,\n isExternal: false,\n originalPath,\n };\n }\n}\n","import type { BlurPlaceholderType } from './types';\n\nexport const DEFAULT_PLACEHOLDERS: Record<BlurPlaceholderType, string> = {\n default:\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUwIiBoZWlnaHQ9IjE1MCIgdmlld0JveD0iMCAwIDE1MCAxNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkaWVudCIgeDE9IjAlIiB5MT0iMCUiIHgyPSIxMDAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3R5bGU9InN0b3AtY29sb3I6IzJhMzIzZDtzdG9wLW9wYWNpdHk6MSIvPjxzdG9wIG9mZnNldD0iNTAlIiBzdHlsZT0ic3RvcC1jb2xvcjojMjEyNzMwO3N0b3Atb3BhY2l0eToxIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdHlsZT0ic3RvcC1jb2xvcjojMTgxZDI0O3N0b3Atb3BhY2l0eToxIi8+PC9saW5lYXJHcmFkaWVudD48L2RlZnM+PHJlY3Qgd2lkdGg9IjE1MCIgaGVpZ2h0PSIxNTAiIGZpbGw9InVybCgjZ3JhZGllbnQpIi8+PC9zdmc+',\n hero:\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkyMCIgaGVpZ2h0PSIxMDgwIiB2aWV3Qm94PSIwIDAgMTkyMCAxMDgwIiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxkZWZzPjxsaW5lYXJHcmFkaWVudCBpZD0iaGVyb0dyYWRpZW50IiB4MT0iMCUiIHkxPSIwJSIgeDI9IjEwMCUiIHkyPSIxMDAlIj48c3RvcCBvZmZzZXQ9IjAlIiBzdHlsZT0ic3RvcC1jb2xvcjojMmQzNzQ4O3N0b3Atb3BhY2l0eToxIi8+PHN0b3Agb2Zmc2V0PSIzMCUiIHN0eWxlPSJzdG9wLWNvbG9yOiMyMzJiMzg7c3RvcC1vcGFjaXR5OjEiLz48c3RvcCBvZmZzZXQ9IjcwJSIgc3R5bGU9InN0b3AtY29sb3I6IzFlMjUzMDtzdG9wLW9wYWNpdHk6MSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3R5bGU9InN0b3AtY29sb3I6IzE3MWQyNztzdG9wLW9wYWNpdHk6MSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHdpZHRoPSIxOTIwIiBoZWlnaHQ9IjEwODAiIGZpbGw9InVybCgjaGVyb0dyYWRpZW50KSIvPjwvc3ZnPg==',\n card:\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAwIiBoZWlnaHQ9IjMwMCIgdmlld0JveD0iMCAwIDQwMCAzMDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJjYXJkR3JhZGllbnQiIHgxPSIwJSIgeTE9IjAlIiB4Mj0iMTAwJSIgeTI9IjEwMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0eWxlPSJzdG9wLWNvbG9yOiMyYTMyM2Q7c3RvcC1vcGFjaXR5OjEiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0eWxlPSJzdG9wLWNvbG9yOiMxYzIyMmI7c3RvcC1vcGFjaXR5OjEiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48cmVjdCB3aWR0aD0iNDAwIiBoZWlnaHQ9IjMwMCIgZmlsbD0idXJsKCNjYXJkR3JhZGllbnQpIi8+PC9zdmc+',\n thumbnail:\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgdmlld0JveD0iMCAwIDEwMCAxMDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHJlY3Qgd2lkdGg9IjEwMCIgaGVpZ2h0PSIxMDAiIGZpbGw9IiMyNDJiMzUiLz48L3N2Zz4=',\n};\n","import { LRUCache } from './lruCache';\nimport { normalizeImagePath, type NormalizePathOptions } from './pathMapper';\nimport { DEFAULT_PLACEHOLDERS } from './placeholders';\nimport type {\n BlurCacheEntry,\n BlurManifestData,\n BlurManifestEntry,\n BlurPlaceholderType,\n BlurServiceMetrics,\n BlurSize,\n} from './types';\n\nexport interface BlurServiceOptions {\n cacheSize?: number;\n manifest?: BlurManifestData | Record<string, BlurManifestEntry>;\n pathOptions?: NormalizePathOptions;\n}\n\nexport class BlurService {\n private blurData: Record<string, BlurManifestEntry>;\n private readonly cache: LRUCache<string, BlurCacheEntry>;\n private readonly pathOptions?: NormalizePathOptions;\n private metadata: {\n version: string;\n generatedAt: string;\n totalImages: number;\n };\n private metrics: BlurServiceMetrics;\n\n constructor(options: BlurServiceOptions = {}) {\n this.blurData = {};\n this.pathOptions = options.pathOptions;\n this.metadata = {\n version: '2.0',\n generatedAt: new Date().toISOString(),\n totalImages: 0,\n };\n this.cache = new LRUCache(options.cacheSize ?? 500);\n this.metrics = {\n totalRequests: 0,\n cacheHits: 0,\n cacheMisses: 0,\n errors: 0,\n };\n\n if (options.manifest) {\n this.loadManifest(options.manifest);\n }\n }\n\n /**\n * Hydrate the service with a generated `blur-hashes.json` manifest or hash map.\n */\n loadManifest(\n manifest: BlurManifestData | Record<string, BlurManifestEntry>,\n ): void {\n this.cache.clear();\n\n if ('hashes' in manifest && typeof manifest.hashes === 'object' && manifest.hashes !== null) {\n const typed = manifest as BlurManifestData;\n this.blurData = { ...typed.hashes };\n this.metadata = {\n version: typed.version || '2.0',\n generatedAt: typed.generatedAt || new Date().toISOString(),\n totalImages: Object.keys(this.blurData).length,\n };\n } else {\n this.blurData = { ...(manifest as Record<string, BlurManifestEntry>) };\n this.metadata = {\n version: '2.0',\n generatedAt: new Date().toISOString(),\n totalImages: Object.keys(this.blurData).length,\n };\n }\n }\n\n /**\n * Register or update a single image's blur data at runtime.\n */\n registerEntry(imagePath: string, entry: BlurManifestEntry): void {\n this.blurData[imagePath] = entry;\n this.metadata.totalImages = Object.keys(this.blurData).length;\n this.cache.clear();\n }\n\n getDefaultPlaceholder(type: BlurPlaceholderType = 'default'): string {\n return DEFAULT_PLACEHOLDERS[type];\n }\n\n private findBlurDataByPath(imageSrc: string): BlurManifestEntry | null {\n let data = this.blurData[imageSrc];\n if (data) return data;\n\n const pathInfo = normalizeImagePath(imageSrc, this.pathOptions);\n data = this.blurData[pathInfo.normalizedPath];\n if (data) return data;\n\n const withSlash = pathInfo.normalizedPath.startsWith('/')\n ? pathInfo.normalizedPath\n : '/' + pathInfo.normalizedPath;\n const withoutSlash = pathInfo.normalizedPath.replace(/^\\/+/, '');\n\n data = this.blurData[withSlash] || this.blurData[withoutSlash];\n if (data) return data;\n\n const firstSlashIdx = withoutSlash.indexOf('/');\n if (firstSlashIdx > 0 && firstSlashIdx < withoutSlash.length - 1) {\n const withoutBucket = withoutSlash.slice(firstSlashIdx + 1);\n data =\n this.blurData['/' + withoutBucket] || this.blurData[withoutBucket];\n if (data) return data;\n }\n\n if (pathInfo.isExternal && pathInfo.originalPath !== imageSrc) {\n data = this.blurData[pathInfo.originalPath];\n if (data) return data;\n }\n\n return null;\n }\n\n getDominantColor(imageSrc: string): string {\n const data = this.findBlurDataByPath(imageSrc);\n return data?.color || '#E5E7EB';\n }\n\n getBlurDataURL(\n imageSrc: string,\n options: {\n type?: BlurPlaceholderType;\n size?: BlurSize;\n } = {},\n ): string {\n const { type = 'default', size = 'small' } = options;\n\n this.metrics.totalRequests++;\n\n const cacheKey = `${imageSrc}-${size}-${type}`;\n if (this.cache.has(cacheKey)) {\n this.metrics.cacheHits++;\n return this.cache.get(cacheKey)!.dataUrl;\n }\n\n this.metrics.cacheMisses++;\n\n if (Object.keys(this.blurData).length === 0) {\n return this.getDefaultPlaceholder(type);\n }\n\n const data = this.findBlurDataByPath(imageSrc);\n if (!data) {\n return this.getDefaultPlaceholder(type);\n }\n\n const blurDataURL =\n data.variants?.[size] ||\n data.variants?.small ||\n this.getDefaultPlaceholder(type);\n\n this.cache.set(cacheKey, {\n dataUrl: blurDataURL,\n timestamp: Date.now(),\n });\n\n return blurDataURL;\n }\n\n getBulkBlurData(\n imageSrcs: string[],\n options: {\n type?: BlurPlaceholderType;\n size?: BlurSize;\n } = {},\n ): Record<string, string> {\n const result: Record<string, string> = {};\n for (const imageSrc of imageSrcs) {\n result[imageSrc] = this.getBlurDataURL(imageSrc, options);\n }\n return result;\n }\n\n getProgressiveData(imageSrc: string, size: BlurSize = 'small') {\n return {\n color: this.getDominantColor(imageSrc),\n blur: this.getBlurDataURL(imageSrc, { size }),\n hasBlur: this.hasBlurHash(imageSrc),\n };\n }\n\n hasBlurHash(imageSrc: string): boolean {\n return Boolean(this.findBlurDataByPath(imageSrc));\n }\n\n getMetadata() {\n const cacheHitRate =\n this.metrics.totalRequests > 0\n ? (\n (this.metrics.cacheHits / this.metrics.totalRequests) *\n 100\n ).toFixed(2)\n : '0.00';\n\n return {\n ...this.metadata,\n cacheSize: this.cache.size,\n metrics: {\n ...this.metrics,\n cacheHitRate: `${cacheHitRate}%`,\n },\n };\n }\n\n clearCache(): void {\n this.cache.clear();\n }\n\n getBlurHash(imageSrc: string): string | null {\n const data = this.findBlurDataByPath(imageSrc);\n return data?.hash || null;\n }\n\n preloadBlurData(imageSrcs: string[], size: BlurSize = 'small'): void {\n for (const imageSrc of imageSrcs) {\n this.getBlurDataURL(imageSrc, { size });\n }\n }\n\n async fetchBlurDataForImage(\n imageSrc: string,\n type: BlurPlaceholderType = 'default',\n ): Promise<string> {\n return Promise.resolve(this.getBlurDataURL(imageSrc, { type }));\n }\n\n getAvailableKeys(): string[] {\n return Object.keys(this.blurData);\n }\n\n findMatchingKeys(searchTerm: string): string[] {\n const lower = searchTerm.toLowerCase();\n return Object.keys(this.blurData).filter((key) =>\n key.toLowerCase().includes(lower),\n );\n }\n}\n\nexport function createBlurService(options?: BlurServiceOptions): BlurService {\n return new BlurService(options);\n}\n\nexport const blurService = new BlurService();\n"],"mappings":"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","names":[]}
@@ -155,4 +155,4 @@ function getFriendlyErrorMessage(error, locale = "en") {
155
155
 
156
156
 
157
157
  exports.QUALITY_PRESETS = QUALITY_PRESETS; exports.formatFileSize = formatFileSize; exports.calculateReduction = calculateReduction; exports.estimateOutputSize = estimateOutputSize; exports.getStatusMessage = getStatusMessage; exports.createSuccessMessage = createSuccessMessage; exports.getFriendlyErrorMessage = getFriendlyErrorMessage;
158
- //# sourceMappingURL=chunk-DFCSN3X7.cjs.map
158
+ //# sourceMappingURL=chunk-KJVYWKIG.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/image-upload-kit/image-upload-kit/dist/chunk-KJVYWKIG.cjs","../src/types/quality.ts","../src/utils/formatters.ts"],"names":[],"mappings":"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","file":"/home/runner/work/image-upload-kit/image-upload-kit/dist/chunk-KJVYWKIG.cjs","sourcesContent":[null,"export type UploadLocale = 'en' | 'ar';\n\nexport type ImageOutputFormat = 'avif' | 'webp' | 'jpeg' | 'png' | 'svg';\n\nexport type ExplicitOutputFormat = 'avif' | 'webp' | 'jpeg' | 'png';\n\nexport type QualityLevel = 'low' | 'medium' | 'high' | 'maximum';\n\nexport interface QualityPreset {\n label: string;\n labelAr: string;\n value: number;\n description: string;\n descriptionAr: string;\n /** Rough fraction of original bytes after modern AVIF/WebP compression */\n compressionRatio: number;\n}\n\nexport const QUALITY_PRESETS: Record<QualityLevel, QualityPreset> = {\n low: {\n label: 'Low',\n labelAr: 'منخفضة',\n value: 50,\n description: 'Smallest file — best for tiny thumbnails and icons',\n descriptionAr: 'أصغر حجم — مناسب للمصغرات والأيقونات الصغيرة',\n compressionRatio: 0.12,\n },\n medium: {\n label: 'Medium',\n labelAr: 'متوسطة',\n value: 72,\n description: 'Balanced size and quality — suitable for most web images',\n descriptionAr: 'توازن بين الحجم والجودة — مناسب لمعظم صور الويب',\n compressionRatio: 0.22,\n },\n high: {\n label: 'High',\n labelAr: 'عالية',\n value: 85,\n description: 'Recommended — sharp visuals with excellent compression',\n descriptionAr: 'موصى به — جودة عالية وضغط ممتاز',\n compressionRatio: 0.3,\n },\n maximum: {\n label: 'Maximum',\n labelAr: 'أقصى جودة',\n value: 95,\n description: 'Closest to original — large file, use for hero / print',\n descriptionAr: 'أقرب للأصل — حجم كبير، مناسب للصور الرئيسية والطباعة',\n compressionRatio: 0.55,\n },\n};\n\nexport interface ImageDimensions {\n width: number;\n height: number;\n}\n","import type { QualityLevel, UploadLocale } from '../types';\nimport { QUALITY_PRESETS } from '../types';\n\nexport function formatFileSize(bytes: number): string {\n if (bytes <= 0) return '0 Bytes';\n const k = 1024;\n const sizes = ['Bytes', 'KB', 'MB', 'GB'];\n const i = Math.min(\n sizes.length - 1,\n Math.floor(Math.log(bytes) / Math.log(k)),\n );\n return `${Math.round((bytes / Math.pow(k, i)) * 100) / 100} ${sizes[i]}`;\n}\n\nexport function calculateReduction(\n original: number,\n optimized: number,\n): number {\n if (original <= 0) return 0;\n return Math.round(((original - optimized) / original) * 100);\n}\n\nexport function estimateOutputSize(\n originalBytes: number,\n level: QualityLevel,\n): number {\n return Math.round(originalBytes * QUALITY_PRESETS[level].compressionRatio);\n}\n\nconst creativeMessages = [\n 'Sprinkling digital magic ✨',\n 'Painting pixels with perfection 🎨',\n 'Launching to the cloud 🚀',\n 'Creating something beautiful ⭐',\n 'Transforming your vision ⚡',\n 'Weaving visual excellence 💫',\n 'Crafting your masterpiece 🎭',\n 'Working our magic 🔮',\n 'Making it pixel-perfect ✨',\n 'Keep calm, creating magic 🎪',\n 'Hitting the sweet spot 🎯',\n 'Artist mode activated 🎨',\n 'Shooting for the stars 🌠',\n 'Compressing with love 💝',\n 'Enhancing quality 💎',\n 'Polishing to perfection ✨',\n];\n\nconst creativeMessagesAr = [\n 'نضيف لمسة رقمية ساحرة ✨',\n 'ننسق البكسلات بإتقان 🎨',\n 'الرفع جارٍ إلى السحابة 🚀',\n 'نصنع شيئاً جميلاً ⭐',\n 'نحوّل رؤيتك إلى واقع ⚡',\n 'نبني تجربة بصرية مميزة 💫',\n 'نصقل عملك باحتراف 🎭',\n 'السحر جارٍ الآن 🔮',\n 'نضبط كل بكسل بعناية ✨',\n 'اهدأ، نحن نهتم بالتفاصيل 🎪',\n 'نقترب من النتيجة المثالية 🎯',\n 'وضع الإبداع مفعل 🎨',\n 'نستهدف أفضل نتيجة 🌠',\n 'ضغط ذكي مع الحفاظ على الجودة 💝',\n 'تحسين الجودة مستمر 💎',\n 'اللمسات الأخيرة قيد التنفيذ ✨',\n];\n\nexport function getStatusMessage(\n progress: number,\n locale: UploadLocale = 'en',\n): string {\n if (progress >= 95) {\n return locale === 'ar' ? '🎉 اقتربنا جداً...' : '🎉 Almost there...';\n }\n if (progress >= 85) {\n return locale === 'ar'\n ? '✨ نضع اللمسات الأخيرة...'\n : '✨ Polishing the final details...';\n }\n\n const list = locale === 'ar' ? creativeMessagesAr : creativeMessages;\n const clampedProgress = Math.max(0, Math.min(99, progress));\n const messageIndex = Math.min(\n list.length - 1,\n Math.floor((clampedProgress / 100) * list.length),\n );\n\n return list[messageIndex];\n}\n\nexport function createSuccessMessage(\n originalSize: number,\n optimizedSize: number,\n compact: boolean = false,\n locale: UploadLocale = 'en',\n): string {\n const reduction = calculateReduction(originalSize, optimizedSize);\n const original = formatFileSize(originalSize);\n const optimized = formatFileSize(optimizedSize);\n\n if (compact) {\n if (reduction > 50) {\n return locale === 'ar'\n ? `🎉 أصغر بنسبة ${reduction}%! (${original} → ${optimized})`\n : `🎉 ${reduction}% smaller! (${original} → ${optimized})`;\n }\n if (reduction > 0) {\n return locale === 'ar'\n ? `✓ أصغر بنسبة ${reduction}% (${original} → ${optimized})`\n : `✓ ${reduction}% smaller (${original} → ${optimized})`;\n }\n return `✓ ${optimized}`;\n }\n\n if (reduction > 70) {\n return locale === 'ar'\n ? `🎉 رائع! تم تقليل الحجم بنسبة ${reduction}% (${original} → ${optimized})`\n : `🎉 Amazing! Reduced by ${reduction}% (${original} → ${optimized})`;\n }\n if (reduction > 50) {\n return locale === 'ar'\n ? `✨ ممتاز! تم تقليل الحجم بنسبة ${reduction}% (${original} → ${optimized})`\n : `✨ Great! Reduced by ${reduction}% (${original} → ${optimized})`;\n }\n if (reduction > 20) {\n return locale === 'ar'\n ? `✓ اكتمل الرفع! تم تقليل الحجم بنسبة ${reduction}% (${original} → ${optimized})`\n : `✓ Upload complete! Reduced by ${reduction}% (${original} → ${optimized})`;\n }\n return locale === 'ar'\n ? `✓ اكتمل الرفع! (${original} → ${optimized})`\n : `✓ Upload complete! (${original} → ${optimized})`;\n}\n\nconst FILE_TYPE_ERROR_REGEX =\n /\\b(?:file\\s+type|mime\\s+type|invalid\\s+type|unsupported|format|mime)\\b/i;\n\nexport function getFriendlyErrorMessage(\n error: string,\n locale: UploadLocale = 'en',\n): string {\n const lower = error.toLowerCase();\n if (\n lower.includes('size') ||\n lower.includes('large') ||\n lower.includes('exceeds')\n ) {\n return locale === 'ar'\n ? 'الملف كبير جداً. يرجى اختيار صورة أصغر.'\n : 'File is too large. Please choose a smaller image.';\n }\n if (\n lower.includes('network') ||\n lower.includes('fetch') ||\n lower.includes('connection')\n ) {\n return locale === 'ar'\n ? 'حدث خطأ في الشبكة. يرجى التحقق من الاتصال والمحاولة مرة أخرى.'\n : 'Network error. Please check your connection and try again.';\n }\n if (lower.includes('timeout') || lower.includes('timed out')) {\n return locale === 'ar'\n ? 'انتهت مهلة الرفع. يرجى المحاولة مرة أخرى.'\n : 'Upload timed out. Please try again.';\n }\n if (FILE_TYPE_ERROR_REGEX.test(error)) {\n return locale === 'ar'\n ? 'نوع الملف غير صالح. يرجى رفع صورة صالحة (JPEG, PNG, WebP, AVIF).'\n : 'Invalid file type. Please upload a valid image (JPEG, PNG, WebP, AVIF).';\n }\n if (error) return error;\n return locale === 'ar'\n ? 'فشل الرفع. يرجى المحاولة مرة أخرى.'\n : 'Upload failed. Please try again.';\n}\n"]}
@@ -223,4 +223,4 @@ function validateMultipleFiles(files, maxSizeMB, currentCount, maxImages, locale
223
223
 
224
224
 
225
225
  exports.SVG_MIME_TYPE = SVG_MIME_TYPE; exports.DEFAULT_ALLOWED_FORMATS = DEFAULT_ALLOWED_FORMATS; exports.RASTER_ALLOWED_FORMATS = RASTER_ALLOWED_FORMATS; exports.DEFAULT_IMAGE_DIMENSIONS = DEFAULT_IMAGE_DIMENSIONS; exports.STANDARD_PRESETS = STANDARD_PRESETS; exports.defineUploadPresets = defineUploadPresets; exports.DEFAULT_BLUR_COLOR = DEFAULT_BLUR_COLOR; exports.normalizeColorInput = normalizeColorInput; exports.hexToRgb = hexToRgb; exports.rgbToHex = rgbToHex; exports.generateColorSvgDataURL = generateColorSvgDataURL; exports.validateImageFileStrict = validateImageFileStrict; exports.validateImageFile = validateImageFile; exports.validateImageFileWithName = validateImageFileWithName; exports.validateMultipleFiles = validateMultipleFiles;
226
- //# sourceMappingURL=chunk-34L4TEE3.cjs.map
226
+ //# sourceMappingURL=chunk-NEDBIIE3.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/image-upload-kit/image-upload-kit/dist/chunk-NEDBIIE3.cjs","../src/types/presets.ts","../src/utils/color.ts","../src/utils/validators.ts"],"names":[],"mappings":"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","file":"/home/runner/work/image-upload-kit/image-upload-kit/dist/chunk-NEDBIIE3.cjs","sourcesContent":[null,"import type {\n ExplicitOutputFormat,\n ImageDimensions,\n QualityLevel,\n} from './quality';\n\n/**\n * Universal visual role presets (project-agnostic).\n * Consumers can define their own presets via `defineUploadPresets` / `createImageUploader({ presets })`\n * or augment `UploadKitRegister` for global type-safety.\n */\nexport type StandardPresetName =\n | 'thumbnail'\n | 'avatar'\n | 'card'\n | 'cover'\n | 'hero'\n | 'logo'\n | 'original';\n\n/**\n * Module augmentation hook for global preset autocomplete across a project:\n * ```ts\n * declare module 'img-upload-kit' {\n * interface UploadKitRegister {\n * presets: 'product-main' | 'product-thumb' | 'user-avatar';\n * }\n * }\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface UploadKitRegister {}\n\nexport type UploadPresetName = UploadKitRegister extends {\n presets: infer TCustom extends string;\n}\n ? TCustom\n : StandardPresetName | (string & {});\n\nexport interface UploadPresetConfig {\n /** Target storage bucket for this preset */\n bucket?: string;\n /** Default folder prefix within the bucket (e.g. 'avatars' or 'products/thumbnails') */\n folder?: string;\n /** Maximum bounding box dimensions (aspect ratio preserved, never enlarged) */\n maxDimensions?: ImageDimensions;\n /** Maximum allowed source file size in MB */\n maxSizeMB?: number;\n /** Allowed source MIME types */\n allowedFormats?: string[];\n /** Force a specific output format; omit for smart size-guarded AVIF/WebP optimization */\n outputFormat?: ExplicitOutputFormat;\n /** Default compression quality (1–100) */\n quality?: number;\n /** Recommended UI quality tab for React `<QualitySelector />` */\n recommendedQualityLevel?: QualityLevel;\n /** Optional guidance note shown in `<QualitySelector />` */\n recommendationNote?: { en: string; ar?: string };\n /** Generate compact BlurHash string alongside WebP LQIP data URL */\n includeBlurHash?: boolean;\n /** Opt-in to allow SVG uploads for this preset (sanitized before storage). Defaults to `false`. */\n allowSvg?: boolean;\n /** Maximum input pixel count allowed by Sharp (defaults to 50 MP = 50,000,000) */\n limitInputPixels?: number;\n /** Responsive variant widths in pixels (e.g. [640, 1024, 1920]); widths >= main image width are skipped */\n variantWidths?: number[];\n /** Optional local directory to mirror uploaded files into */\n mirrorDir?: string;\n /** Optional public URL prefix when `mirrorDir` is used */\n publicUrlBase?: string;\n}\n\nexport const SVG_MIME_TYPE = 'image/svg+xml';\n\nexport const DEFAULT_ALLOWED_FORMATS: string[] = [\n 'image/jpeg',\n 'image/png',\n 'image/webp',\n 'image/avif',\n];\n\nexport const RASTER_ALLOWED_FORMATS: string[] = [\n 'image/jpeg',\n 'image/png',\n 'image/webp',\n 'image/avif',\n];\n\nexport const DEFAULT_IMAGE_DIMENSIONS: ImageDimensions = {\n width: 1920,\n height: 1080,\n};\n\nexport const STANDARD_PRESETS: Record<StandardPresetName, UploadPresetConfig> = {\n thumbnail: {\n folder: 'thumbnails',\n maxDimensions: { width: 600, height: 600 },\n maxSizeMB: 5,\n quality: 78,\n recommendedQualityLevel: 'medium',\n allowedFormats: RASTER_ALLOWED_FORMATS,\n recommendationNote: {\n en: 'Thumbnails display at compact sizes — Medium quality keeps pages fast',\n ar: 'المصغرات تعرض بأحجام صغيرة — الجودة المتوسطة تحافظ على سرعة الصفحة',\n },\n },\n avatar: {\n folder: 'avatars',\n maxDimensions: { width: 512, height: 512 },\n maxSizeMB: 5,\n quality: 80,\n recommendedQualityLevel: 'medium',\n allowedFormats: RASTER_ALLOWED_FORMATS,\n recommendationNote: {\n en: 'Avatars display small — Medium quality balances sharpness and speed',\n ar: 'الصور الشخصية صغيرة — الجودة المتوسطة توازن بين الوضوح والسرعة',\n },\n },\n card: {\n folder: 'cards',\n maxDimensions: { width: 1200, height: 900 },\n maxSizeMB: 8,\n quality: 85,\n recommendedQualityLevel: 'high',\n allowedFormats: DEFAULT_ALLOWED_FORMATS,\n },\n cover: {\n folder: 'covers',\n maxDimensions: { width: 1920, height: 1080 },\n maxSizeMB: 10,\n quality: 88,\n recommendedQualityLevel: 'high',\n allowedFormats: DEFAULT_ALLOWED_FORMATS,\n },\n hero: {\n folder: 'hero',\n maxDimensions: { width: 2560, height: 1440 },\n maxSizeMB: 15,\n quality: 92,\n recommendedQualityLevel: 'maximum',\n allowedFormats: DEFAULT_ALLOWED_FORMATS,\n recommendationNote: {\n en: 'Full-width hero visuals benefit from Maximum quality to preserve fine detail',\n ar: 'الصور الرئيسية بعرض كامل تستفيد من الجودة القصوى للحفاظ على التفاصيل الدقيقة',\n },\n },\n logo: {\n folder: 'logos',\n maxDimensions: { width: 800, height: 800 },\n maxSizeMB: 5,\n quality: 90,\n recommendedQualityLevel: 'high',\n allowedFormats: DEFAULT_ALLOWED_FORMATS,\n recommendationNote: {\n en: 'Prefer SVG for vector logos — High quality preserves crisp edges on raster logos',\n ar: 'يفضل SVG للشعارات المتجهة — الجودة العالية تحافظ على حواف واضحة',\n },\n },\n original: {\n folder: 'originals',\n maxDimensions: { width: 4096, height: 4096 },\n maxSizeMB: 25,\n quality: 95,\n recommendedQualityLevel: 'maximum',\n allowedFormats: DEFAULT_ALLOWED_FORMATS,\n },\n};\n\n/**\n * Type-safe helper to define project-specific upload presets with full key inference.\n */\nexport function defineUploadPresets<\n T extends Record<string, UploadPresetConfig>,\n>(presets: T): T {\n return presets;\n}\n","export const DEFAULT_BLUR_COLOR = '#F5F5F5';\n\nexport function normalizeColorInput(value?: string | null): string | null {\n if (!value) return null;\n let next = value.trim();\n if (!next) return null;\n if (!next.startsWith('#')) {\n next = `#${next}`;\n }\n const threeHex = /^#([0-9a-fA-F]{3})$/;\n const sixHex = /^#([0-9a-fA-F]{6})$/;\n if (threeHex.test(next)) {\n const [, triplet] = next.match(threeHex) ?? [];\n if (triplet) {\n next = `#${triplet\n .split('')\n .map((char) => char + char)\n .join('')}`;\n }\n } else if (!sixHex.test(next)) {\n return null;\n }\n return next.toUpperCase();\n}\n\nexport function hexToRgb(hex: string): { r: number; g: number; b: number } {\n const normalized = hex.replace('#', '');\n const expanded =\n normalized.length === 3\n ? normalized\n .split('')\n .map((char) => char + char)\n .join('')\n : normalized;\n const padded = expanded.padEnd(6, '0').slice(0, 6);\n const value = Number.parseInt(padded, 16);\n if (Number.isNaN(value)) {\n return { r: 245, g: 245, b: 245 };\n }\n return {\n r: (value >> 16) & 255,\n g: (value >> 8) & 255,\n b: value & 255,\n };\n}\n\nexport function rgbToHex(r: number, g: number, b: number): string {\n const clamp = (v: number) => Math.max(0, Math.min(255, Math.round(v)));\n const value = (clamp(r) << 16) | (clamp(g) << 8) | clamp(b);\n return `#${value.toString(16).padStart(6, '0').toUpperCase()}`;\n}\n\nfunction encodeBase64Ascii(str: string): string {\n if (typeof btoa === 'function') {\n return btoa(str);\n }\n return Buffer.from(str, 'utf8').toString('base64');\n}\n\nexport function generateColorSvgDataURL(color: string = DEFAULT_BLUR_COLOR): string {\n const safeColor = normalizeColorInput(color) || DEFAULT_BLUR_COLOR;\n const svg = `<svg width=\"100\" height=\"100\" xmlns=\"http://www.w3.org/2000/svg\"><rect width=\"100%\" height=\"100%\" fill=\"${safeColor}\"/></svg>`;\n return `data:image/svg+xml;base64,${encodeBase64Ascii(svg)}`;\n}\n","import type { UploadLocale } from '../types';\n\nexport interface FileLike {\n name?: string;\n size: number;\n type: string;\n}\n\nexport function validateImageFileStrict(\n file: FileLike,\n maxSizeMB: number,\n allowedFormats: string[],\n): { valid: boolean; error?: string } {\n const maxBytes = maxSizeMB * 1024 * 1024;\n if (file.size > maxBytes) {\n return {\n valid: false,\n error: `File size (${(file.size / 1024 / 1024).toFixed(2)}MB) exceeds maximum of ${maxSizeMB}MB`,\n };\n }\n\n if (allowedFormats.length > 0 && !allowedFormats.includes(file.type)) {\n return {\n valid: false,\n error: `File type ${file.type || 'unknown'} is not allowed. Allowed: ${allowedFormats.join(', ')}`,\n };\n }\n\n return { valid: true };\n}\n\nexport function validateImageFile(\n file: FileLike,\n maxSizeMB: number,\n locale: UploadLocale = 'en',\n allowedFormats?: string[],\n): string | null {\n if (!file.type || !file.type.startsWith('image/')) {\n return locale === 'ar'\n ? 'يرجى اختيار ملف صورة صالح'\n : 'Please select a valid image file';\n }\n\n if (allowedFormats && allowedFormats.length > 0 && !allowedFormats.includes(file.type)) {\n return locale === 'ar'\n ? `صيغة الملف غير مدعومة (${file.type})`\n : `Unsupported image format (${file.type})`;\n }\n\n const fileSizeMB = file.size / (1024 * 1024);\n if (fileSizeMB > maxSizeMB) {\n return locale === 'ar'\n ? `يجب ألا يتجاوز حجم الملف ${maxSizeMB}MB`\n : `File size must be less than ${maxSizeMB}MB`;\n }\n\n return null;\n}\n\nexport function validateImageFileWithName(\n file: FileLike & { name: string },\n maxSizeMB: number,\n locale: UploadLocale = 'en',\n): string | null {\n if (!file.type || !file.type.startsWith('image/')) {\n return locale === 'ar'\n ? `${file.name}: ليس ملف صورة صالحاً`\n : `${file.name}: Not a valid image file`;\n }\n\n const fileSizeMB = file.size / (1024 * 1024);\n if (fileSizeMB > maxSizeMB) {\n return locale === 'ar'\n ? `${file.name}: يجب ألا يتجاوز حجم الملف ${maxSizeMB}MB`\n : `${file.name}: File size must be less than ${maxSizeMB}MB`;\n }\n\n return null;\n}\n\nexport function validateMultipleFiles(\n files: Array<FileLike & { name: string }>,\n maxSizeMB: number,\n currentCount: number,\n maxImages: number,\n locale: UploadLocale = 'en',\n): string | null {\n if (currentCount + files.length > maxImages) {\n return locale === 'ar'\n ? `يمكن رفع ${maxImages} صورة فقط. المتبقي: ${maxImages - currentCount}.`\n : `Can only upload ${maxImages} images. ${maxImages - currentCount} remaining.`;\n }\n\n const oversizedFiles: string[] = [];\n for (const file of files) {\n const fileSizeMB = file.size / (1024 * 1024);\n if (fileSizeMB > maxSizeMB) {\n oversizedFiles.push(file.name);\n }\n }\n\n if (oversizedFiles.length > 0) {\n if (locale === 'ar') {\n return `الملفات التالية أكبر من الحد المسموح (${maxSizeMB}MB): ${oversizedFiles.join(', ')}`;\n }\n return `The following file${\n oversizedFiles.length > 1 ? 's are' : ' is'\n } too large (max ${maxSizeMB}MB): ${oversizedFiles.join(', ')}`;\n }\n\n return null;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["e:\\Personal-Projects\\image-upload-kit\\dist\\chunk-QHU7FUO4.cjs"],"names":[],"mappings":"AAAA;AACA,IAAI,8BAA8B,EAAE,4BAA4B;AAChE,SAAS,qBAAqB,CAAC,GAAG,EAAE,aAAa,EAAE,6BAA6B,EAAE;AAClF,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,OAAO,IAAI;AACvB,EAAE,IAAI;AACN,IAAI,MAAM,OAAO,EAAE,IAAI,GAAG,CAAC,GAAG,EAAE,kBAAkB,CAAC;AACnD,IAAI,MAAM,SAAS,EAAE,MAAM,CAAC,QAAQ;AACpC,IAAI,MAAM,YAAY,EAAE,QAAQ,CAAC,OAAO,CAAC,YAAY,CAAC;AACtD,IAAI,GAAG,CAAC,YAAY,IAAI,CAAC,CAAC,EAAE;AAC5B,MAAM,OAAO,IAAI;AACjB,IAAI;AACJ,IAAI,MAAM,aAAa,EAAE,QAAQ,CAAC,KAAK,CAAC,YAAY,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;AAC9F,IAAI,MAAM,SAAS,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;AAC5D,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE;AAC7B,MAAM,OAAO,IAAI;AACjB,IAAI;AACJ,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,SAAS,EAAE,EAAE,QAAQ;AAC3C,IAAI,MAAM,SAAS,EAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;AACxC,IAAI,MAAM,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC;AACpD,IAAI,MAAM,aAAa,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC;AAClD,IAAI,MAAM,UAAU,EAAE,aAAa,GAAG,EAAE,EAAE,QAAQ,CAAC,KAAK,CAAC,YAAY,EAAE,EAAE,IAAI;AAC7E,IAAI,OAAO;AACX,MAAM,MAAM;AACZ,MAAM,IAAI,EAAE,QAAQ;AACpB,MAAM,QAAQ;AACd,MAAM;AACN,IAAI,CAAC;AACL,EAAE,EAAE,UAAM;AACV,IAAI,OAAO,IAAI;AACf,EAAE;AACF;AACA;AACA;AACE;AACA;AACF,6HAAC","file":"E:\\Personal-Projects\\image-upload-kit\\dist\\chunk-QHU7FUO4.cjs","sourcesContent":[null]}
1
+ {"version":3,"sources":["/home/runner/work/image-upload-kit/image-upload-kit/dist/chunk-QHU7FUO4.cjs","../src/storage/urlParser.ts"],"names":[],"mappings":"AAAA;ACOO,IAAM,8BAAA,EAAgC,4BAAA;AAEtC,SAAS,qBAAA,CACd,GAAA,EACA,aAAA,EAAuB,6BAAA,EACG;AAC1B,EAAA,GAAA,CAAI,CAAC,GAAA,EAAK,OAAO,IAAA;AAEjB,EAAA,IAAI;AACF,IAAA,MAAM,OAAA,EAAS,IAAI,GAAA,CAAI,GAAA,EAAK,kBAAkB,CAAA;AAC9C,IAAA,MAAM,SAAA,EAAW,MAAA,CAAO,QAAA;AACxB,IAAA,MAAM,YAAA,EAAc,QAAA,CAAS,OAAA,CAAQ,YAAY,CAAA;AAEjD,IAAA,GAAA,CAAI,YAAA,IAAgB,CAAA,CAAA,EAAI;AACtB,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,MAAM,aAAA,EAAe,QAAA,CAClB,KAAA,CAAM,YAAA,EAAc,YAAA,CAAa,MAAM,CAAA,CACvC,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA;AAErB,IAAA,MAAM,SAAA,EAAW,YAAA,CAAa,KAAA,CAAM,GAAG,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA;AACvD,IAAA,GAAA,CAAI,QAAA,CAAS,OAAA,EAAS,CAAA,EAAG;AACvB,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,MAAM,CAAC,MAAA,EAAQ,GAAG,SAAS,EAAA,EAAI,QAAA;AAC/B,IAAA,MAAM,SAAA,EAAW,SAAA,CAAU,IAAA,CAAK,GAAG,CAAA;AACnC,IAAA,MAAM,SAAA,EAAW,SAAA,CAAU,SAAA,CAAU,OAAA,EAAS,CAAC,CAAA;AAC/C,IAAA,MAAM,aAAA,EAAe,QAAA,CAAS,WAAA,CAAY,GAAG,CAAA;AAC7C,IAAA,MAAM,UAAA,EAAY,aAAA,GAAgB,EAAA,EAAI,QAAA,CAAS,KAAA,CAAM,YAAY,EAAA,EAAI,IAAA;AAErE,IAAA,OAAO;AAAA,MACL,MAAA;AAAA,MACA,IAAA,EAAM,QAAA;AAAA,MACN,QAAA;AAAA,MACA;AAAA,IACF,CAAA;AAAA,EACF,EAAA,UAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;ADjBA;AACA;AACE;AACA;AACF,6HAAC","file":"/home/runner/work/image-upload-kit/image-upload-kit/dist/chunk-QHU7FUO4.cjs","sourcesContent":[null,"export interface PublicStorageInfo {\n bucket: string;\n path: string;\n filename: string;\n extension: string | null;\n}\n\nexport const DEFAULT_PUBLIC_STORAGE_PREFIX = '/storage/v1/object/public/';\n\nexport function parsePublicStorageUrl(\n url?: string | null,\n publicPrefix: string = DEFAULT_PUBLIC_STORAGE_PREFIX,\n): PublicStorageInfo | null {\n if (!url) return null;\n\n try {\n const parsed = new URL(url, 'http://localhost');\n const pathname = parsed.pathname;\n const prefixIndex = pathname.indexOf(publicPrefix);\n\n if (prefixIndex === -1) {\n return null;\n }\n\n const relativePath = pathname\n .slice(prefixIndex + publicPrefix.length)\n .replace(/^\\/+/, '');\n\n const segments = relativePath.split('/').filter(Boolean);\n if (segments.length < 2) {\n return null;\n }\n\n const [bucket, ...pathParts] = segments;\n const filePath = pathParts.join('/');\n const filename = pathParts[pathParts.length - 1];\n const lastDotIndex = filename.lastIndexOf('.');\n const extension = lastDotIndex >= 0 ? filename.slice(lastDotIndex) : null;\n\n return {\n bucket,\n path: filePath,\n filename,\n extension,\n };\n } catch {\n return null;\n }\n}\n"]}
@@ -132,4 +132,4 @@ export {
132
132
  extractImageUrls,
133
133
  decodeBlurHashToDataURL
134
134
  };
135
- //# sourceMappingURL=chunk-VYVZVUNI.js.map
135
+ //# sourceMappingURL=chunk-QQHZJKNA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/blur/blurDataUtils.ts"],"sourcesContent":["import { decode as decodeBlurHash, isBlurhashValid } from 'blurhash';\nimport type { BlurData, BlurImageSource } from './types';\n\nexport interface BlurPlaceholderStyle {\n backgroundColor: string;\n backgroundImage?: string;\n backgroundSize?: string;\n backgroundPosition?: string;\n backgroundRepeat?: string;\n filter?: string;\n transform?: string;\n}\n\nfunction formatCssUrl(rawUrl: string): string {\n const escaped = rawUrl\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\"/g, '\\\\\"')\n .replace(/[\\r\\n]/g, '');\n return `url(\"${escaped}\")`;\n}\n\nexport function getBlurData(\n image: BlurImageSource | null | undefined,\n): BlurData {\n if (!image) {\n return {\n blurDataUrl: '',\n blurColor: '#E5E7EB',\n hasBlur: false,\n };\n }\n\n return {\n blurDataUrl: image.blurDataUrl || '',\n blurColor: image.blurColor || '#E5E7EB',\n ...(image.blurHash ? { blurHash: image.blurHash } : {}),\n hasBlur: Boolean(image.blurDataUrl || image.blurHash),\n };\n}\n\nexport function getImagePropsWithBlur(\n image: BlurImageSource | null | undefined,\n) {\n if (!image?.url) {\n return null;\n }\n\n const blurData = getBlurData(image);\n\n return {\n src: image.url,\n alt: image.altText || '',\n width: image.width || 1920,\n height: image.height || 1080,\n ...(blurData.blurDataUrl && {\n placeholder: 'blur' as const,\n blurDataURL: blurData.blurDataUrl,\n }),\n };\n}\n\nexport function getBackgroundPropsWithBlur(\n image: BlurImageSource | null | undefined,\n): BlurPlaceholderStyle {\n if (!image?.url) {\n return {\n backgroundColor: '#E5E7EB',\n };\n }\n\n const blurData = getBlurData(image);\n\n return {\n backgroundColor: blurData.blurColor,\n backgroundImage: formatCssUrl(image.url),\n backgroundSize: 'cover',\n backgroundPosition: 'center',\n backgroundRepeat: 'no-repeat',\n };\n}\n\nexport function getBlurPlaceholderStyle(\n image: BlurImageSource | null | undefined,\n): BlurPlaceholderStyle {\n const blurData = getBlurData(image);\n\n if (!blurData.blurDataUrl) {\n return {\n backgroundColor: blurData.blurColor,\n };\n }\n\n return {\n backgroundColor: blurData.blurColor,\n backgroundImage: formatCssUrl(blurData.blurDataUrl),\n backgroundSize: 'cover',\n backgroundPosition: 'center',\n filter: 'blur(20px)',\n transform: 'scale(1.1)',\n };\n}\n\nexport function hasBlurData(\n image: BlurImageSource | null | undefined,\n): boolean {\n return Boolean(image?.blurDataUrl || image?.blurColor || image?.blurHash);\n}\n\nexport function getBulkBlurData(\n images: Array<BlurImageSource | null | undefined>,\n): BlurData[] {\n return images.map(getBlurData);\n}\n\n/**\n * Builds a responsive `srcset` descriptor for the full-resolution image URL.\n * Never includes the low-resolution LQIP placeholder in `srcset` so browsers\n * cannot accidentally select the blurred placeholder as the final image.\n */\nexport function createSrcSetWithBlur(\n image: BlurImageSource | null | undefined,\n): string {\n if (!image?.url) return '';\n if (image.width && image.width > 0) {\n return `${image.url} ${image.width}w`;\n }\n return image.url;\n}\n\n/**\n * Preloads the target image URL in `document.head` via `<link rel=\"preload\" as=\"image\">`.\n * Does not set `imagesrcset` to the LQIP data URL and deduplicates existing preload links.\n */\nexport function preloadImageWithBlur(\n image: BlurImageSource | null | undefined,\n): void {\n if (!image?.url || typeof document === 'undefined' || !document.head) return;\n\n const existingLinks = document.head.querySelectorAll(\n 'link[rel=\"preload\"][as=\"image\"]',\n );\n for (let i = 0; i < existingLinks.length; i++) {\n const el = existingLinks[i] as HTMLLinkElement;\n if (el.getAttribute('href') === image.url || el.href === image.url) {\n return;\n }\n }\n\n const link = document.createElement('link');\n link.rel = 'preload';\n link.as = 'image';\n link.href = image.url;\n document.head.appendChild(link);\n}\n\nexport function extractImageUrls(\n image: BlurImageSource | null | undefined,\n): string[] {\n if (!image?.url) return [];\n return [image.url];\n}\n\n/**\n * Browser helper: Decodes a compact BlurHash string (e.g. \"LEHV6nWB2yk8pyo0adR*.7kCMdnj\")\n * into a `data:image/png;base64,...` URL using an offscreen `<canvas>`.\n */\nexport function decodeBlurHashToDataURL(\n hash: string,\n width: number = 32,\n height: number = 32,\n punch: number = 1,\n): string | null {\n if (!hash || typeof document === 'undefined') return null;\n const validation = isBlurhashValid(hash);\n if (!validation.result) return null;\n\n try {\n const pixels = decodeBlurHash(hash, width, height, punch);\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) return null;\n const imageData = ctx.createImageData(width, height);\n imageData.data.set(pixels);\n ctx.putImageData(imageData, 0, 0);\n return canvas.toDataURL('image/png');\n } catch {\n return null;\n }\n}\n"],"mappings":"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","names":[]}
@@ -223,4 +223,4 @@ export {
223
223
  validateImageFileWithName,
224
224
  validateMultipleFiles
225
225
  };
226
- //# sourceMappingURL=chunk-HILELQGS.js.map
226
+ //# sourceMappingURL=chunk-TT5C7K3Q.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types/presets.ts","../src/utils/color.ts","../src/utils/validators.ts"],"sourcesContent":["import type {\n ExplicitOutputFormat,\n ImageDimensions,\n QualityLevel,\n} from './quality';\n\n/**\n * Universal visual role presets (project-agnostic).\n * Consumers can define their own presets via `defineUploadPresets` / `createImageUploader({ presets })`\n * or augment `UploadKitRegister` for global type-safety.\n */\nexport type StandardPresetName =\n | 'thumbnail'\n | 'avatar'\n | 'card'\n | 'cover'\n | 'hero'\n | 'logo'\n | 'original';\n\n/**\n * Module augmentation hook for global preset autocomplete across a project:\n * ```ts\n * declare module 'img-upload-kit' {\n * interface UploadKitRegister {\n * presets: 'product-main' | 'product-thumb' | 'user-avatar';\n * }\n * }\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface UploadKitRegister {}\n\nexport type UploadPresetName = UploadKitRegister extends {\n presets: infer TCustom extends string;\n}\n ? TCustom\n : StandardPresetName | (string & {});\n\nexport interface UploadPresetConfig {\n /** Target storage bucket for this preset */\n bucket?: string;\n /** Default folder prefix within the bucket (e.g. 'avatars' or 'products/thumbnails') */\n folder?: string;\n /** Maximum bounding box dimensions (aspect ratio preserved, never enlarged) */\n maxDimensions?: ImageDimensions;\n /** Maximum allowed source file size in MB */\n maxSizeMB?: number;\n /** Allowed source MIME types */\n allowedFormats?: string[];\n /** Force a specific output format; omit for smart size-guarded AVIF/WebP optimization */\n outputFormat?: ExplicitOutputFormat;\n /** Default compression quality (1–100) */\n quality?: number;\n /** Recommended UI quality tab for React `<QualitySelector />` */\n recommendedQualityLevel?: QualityLevel;\n /** Optional guidance note shown in `<QualitySelector />` */\n recommendationNote?: { en: string; ar?: string };\n /** Generate compact BlurHash string alongside WebP LQIP data URL */\n includeBlurHash?: boolean;\n /** Opt-in to allow SVG uploads for this preset (sanitized before storage). Defaults to `false`. */\n allowSvg?: boolean;\n /** Maximum input pixel count allowed by Sharp (defaults to 50 MP = 50,000,000) */\n limitInputPixels?: number;\n /** Responsive variant widths in pixels (e.g. [640, 1024, 1920]); widths >= main image width are skipped */\n variantWidths?: number[];\n /** Optional local directory to mirror uploaded files into */\n mirrorDir?: string;\n /** Optional public URL prefix when `mirrorDir` is used */\n publicUrlBase?: string;\n}\n\nexport const SVG_MIME_TYPE = 'image/svg+xml';\n\nexport const DEFAULT_ALLOWED_FORMATS: string[] = [\n 'image/jpeg',\n 'image/png',\n 'image/webp',\n 'image/avif',\n];\n\nexport const RASTER_ALLOWED_FORMATS: string[] = [\n 'image/jpeg',\n 'image/png',\n 'image/webp',\n 'image/avif',\n];\n\nexport const DEFAULT_IMAGE_DIMENSIONS: ImageDimensions = {\n width: 1920,\n height: 1080,\n};\n\nexport const STANDARD_PRESETS: Record<StandardPresetName, UploadPresetConfig> = {\n thumbnail: {\n folder: 'thumbnails',\n maxDimensions: { width: 600, height: 600 },\n maxSizeMB: 5,\n quality: 78,\n recommendedQualityLevel: 'medium',\n allowedFormats: RASTER_ALLOWED_FORMATS,\n recommendationNote: {\n en: 'Thumbnails display at compact sizes — Medium quality keeps pages fast',\n ar: 'المصغرات تعرض بأحجام صغيرة — الجودة المتوسطة تحافظ على سرعة الصفحة',\n },\n },\n avatar: {\n folder: 'avatars',\n maxDimensions: { width: 512, height: 512 },\n maxSizeMB: 5,\n quality: 80,\n recommendedQualityLevel: 'medium',\n allowedFormats: RASTER_ALLOWED_FORMATS,\n recommendationNote: {\n en: 'Avatars display small — Medium quality balances sharpness and speed',\n ar: 'الصور الشخصية صغيرة — الجودة المتوسطة توازن بين الوضوح والسرعة',\n },\n },\n card: {\n folder: 'cards',\n maxDimensions: { width: 1200, height: 900 },\n maxSizeMB: 8,\n quality: 85,\n recommendedQualityLevel: 'high',\n allowedFormats: DEFAULT_ALLOWED_FORMATS,\n },\n cover: {\n folder: 'covers',\n maxDimensions: { width: 1920, height: 1080 },\n maxSizeMB: 10,\n quality: 88,\n recommendedQualityLevel: 'high',\n allowedFormats: DEFAULT_ALLOWED_FORMATS,\n },\n hero: {\n folder: 'hero',\n maxDimensions: { width: 2560, height: 1440 },\n maxSizeMB: 15,\n quality: 92,\n recommendedQualityLevel: 'maximum',\n allowedFormats: DEFAULT_ALLOWED_FORMATS,\n recommendationNote: {\n en: 'Full-width hero visuals benefit from Maximum quality to preserve fine detail',\n ar: 'الصور الرئيسية بعرض كامل تستفيد من الجودة القصوى للحفاظ على التفاصيل الدقيقة',\n },\n },\n logo: {\n folder: 'logos',\n maxDimensions: { width: 800, height: 800 },\n maxSizeMB: 5,\n quality: 90,\n recommendedQualityLevel: 'high',\n allowedFormats: DEFAULT_ALLOWED_FORMATS,\n recommendationNote: {\n en: 'Prefer SVG for vector logos — High quality preserves crisp edges on raster logos',\n ar: 'يفضل SVG للشعارات المتجهة — الجودة العالية تحافظ على حواف واضحة',\n },\n },\n original: {\n folder: 'originals',\n maxDimensions: { width: 4096, height: 4096 },\n maxSizeMB: 25,\n quality: 95,\n recommendedQualityLevel: 'maximum',\n allowedFormats: DEFAULT_ALLOWED_FORMATS,\n },\n};\n\n/**\n * Type-safe helper to define project-specific upload presets with full key inference.\n */\nexport function defineUploadPresets<\n T extends Record<string, UploadPresetConfig>,\n>(presets: T): T {\n return presets;\n}\n","export const DEFAULT_BLUR_COLOR = '#F5F5F5';\n\nexport function normalizeColorInput(value?: string | null): string | null {\n if (!value) return null;\n let next = value.trim();\n if (!next) return null;\n if (!next.startsWith('#')) {\n next = `#${next}`;\n }\n const threeHex = /^#([0-9a-fA-F]{3})$/;\n const sixHex = /^#([0-9a-fA-F]{6})$/;\n if (threeHex.test(next)) {\n const [, triplet] = next.match(threeHex) ?? [];\n if (triplet) {\n next = `#${triplet\n .split('')\n .map((char) => char + char)\n .join('')}`;\n }\n } else if (!sixHex.test(next)) {\n return null;\n }\n return next.toUpperCase();\n}\n\nexport function hexToRgb(hex: string): { r: number; g: number; b: number } {\n const normalized = hex.replace('#', '');\n const expanded =\n normalized.length === 3\n ? normalized\n .split('')\n .map((char) => char + char)\n .join('')\n : normalized;\n const padded = expanded.padEnd(6, '0').slice(0, 6);\n const value = Number.parseInt(padded, 16);\n if (Number.isNaN(value)) {\n return { r: 245, g: 245, b: 245 };\n }\n return {\n r: (value >> 16) & 255,\n g: (value >> 8) & 255,\n b: value & 255,\n };\n}\n\nexport function rgbToHex(r: number, g: number, b: number): string {\n const clamp = (v: number) => Math.max(0, Math.min(255, Math.round(v)));\n const value = (clamp(r) << 16) | (clamp(g) << 8) | clamp(b);\n return `#${value.toString(16).padStart(6, '0').toUpperCase()}`;\n}\n\nfunction encodeBase64Ascii(str: string): string {\n if (typeof btoa === 'function') {\n return btoa(str);\n }\n return Buffer.from(str, 'utf8').toString('base64');\n}\n\nexport function generateColorSvgDataURL(color: string = DEFAULT_BLUR_COLOR): string {\n const safeColor = normalizeColorInput(color) || DEFAULT_BLUR_COLOR;\n const svg = `<svg width=\"100\" height=\"100\" xmlns=\"http://www.w3.org/2000/svg\"><rect width=\"100%\" height=\"100%\" fill=\"${safeColor}\"/></svg>`;\n return `data:image/svg+xml;base64,${encodeBase64Ascii(svg)}`;\n}\n","import type { UploadLocale } from '../types';\n\nexport interface FileLike {\n name?: string;\n size: number;\n type: string;\n}\n\nexport function validateImageFileStrict(\n file: FileLike,\n maxSizeMB: number,\n allowedFormats: string[],\n): { valid: boolean; error?: string } {\n const maxBytes = maxSizeMB * 1024 * 1024;\n if (file.size > maxBytes) {\n return {\n valid: false,\n error: `File size (${(file.size / 1024 / 1024).toFixed(2)}MB) exceeds maximum of ${maxSizeMB}MB`,\n };\n }\n\n if (allowedFormats.length > 0 && !allowedFormats.includes(file.type)) {\n return {\n valid: false,\n error: `File type ${file.type || 'unknown'} is not allowed. Allowed: ${allowedFormats.join(', ')}`,\n };\n }\n\n return { valid: true };\n}\n\nexport function validateImageFile(\n file: FileLike,\n maxSizeMB: number,\n locale: UploadLocale = 'en',\n allowedFormats?: string[],\n): string | null {\n if (!file.type || !file.type.startsWith('image/')) {\n return locale === 'ar'\n ? 'يرجى اختيار ملف صورة صالح'\n : 'Please select a valid image file';\n }\n\n if (allowedFormats && allowedFormats.length > 0 && !allowedFormats.includes(file.type)) {\n return locale === 'ar'\n ? `صيغة الملف غير مدعومة (${file.type})`\n : `Unsupported image format (${file.type})`;\n }\n\n const fileSizeMB = file.size / (1024 * 1024);\n if (fileSizeMB > maxSizeMB) {\n return locale === 'ar'\n ? `يجب ألا يتجاوز حجم الملف ${maxSizeMB}MB`\n : `File size must be less than ${maxSizeMB}MB`;\n }\n\n return null;\n}\n\nexport function validateImageFileWithName(\n file: FileLike & { name: string },\n maxSizeMB: number,\n locale: UploadLocale = 'en',\n): string | null {\n if (!file.type || !file.type.startsWith('image/')) {\n return locale === 'ar'\n ? `${file.name}: ليس ملف صورة صالحاً`\n : `${file.name}: Not a valid image file`;\n }\n\n const fileSizeMB = file.size / (1024 * 1024);\n if (fileSizeMB > maxSizeMB) {\n return locale === 'ar'\n ? `${file.name}: يجب ألا يتجاوز حجم الملف ${maxSizeMB}MB`\n : `${file.name}: File size must be less than ${maxSizeMB}MB`;\n }\n\n return null;\n}\n\nexport function validateMultipleFiles(\n files: Array<FileLike & { name: string }>,\n maxSizeMB: number,\n currentCount: number,\n maxImages: number,\n locale: UploadLocale = 'en',\n): string | null {\n if (currentCount + files.length > maxImages) {\n return locale === 'ar'\n ? `يمكن رفع ${maxImages} صورة فقط. المتبقي: ${maxImages - currentCount}.`\n : `Can only upload ${maxImages} images. ${maxImages - currentCount} remaining.`;\n }\n\n const oversizedFiles: string[] = [];\n for (const file of files) {\n const fileSizeMB = file.size / (1024 * 1024);\n if (fileSizeMB > maxSizeMB) {\n oversizedFiles.push(file.name);\n }\n }\n\n if (oversizedFiles.length > 0) {\n if (locale === 'ar') {\n return `الملفات التالية أكبر من الحد المسموح (${maxSizeMB}MB): ${oversizedFiles.join(', ')}`;\n }\n return `The following file${\n oversizedFiles.length > 1 ? 's are' : ' is'\n } too large (max ${maxSizeMB}MB): ${oversizedFiles.join(', ')}`;\n }\n\n return null;\n}\n"],"mappings":"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","names":[]}
@@ -3,14 +3,14 @@
3
3
 
4
4
 
5
5
 
6
- var _chunkDFCSN3X7cjs = require('./chunk-DFCSN3X7.cjs');
6
+ var _chunkKJVYWKIGcjs = require('./chunk-KJVYWKIG.cjs');
7
7
 
8
8
 
9
9
 
10
10
 
11
11
 
12
12
 
13
- var _chunk34L4TEE3cjs = require('./chunk-34L4TEE3.cjs');
13
+ var _chunkNEDBIIE3cjs = require('./chunk-NEDBIIE3.cjs');
14
14
 
15
15
  // src/react/hooks/useClipboardPaste.ts
16
16
  var _react = require('react');
@@ -653,7 +653,7 @@ function buildSingleImagePayload(params, overrides = {}) {
653
653
  const base = uploadedData ? { ...uploadedData } : objVal ? { ...objVal } : typeof value === "string" && value.trim() ? {
654
654
  url: value,
655
655
  blurDataUrl: "",
656
- blurColor: _chunk34L4TEE3cjs.DEFAULT_BLUR_COLOR,
656
+ blurColor: _chunkNEDBIIE3cjs.DEFAULT_BLUR_COLOR,
657
657
  altText: "",
658
658
  width: 0,
659
659
  height: 0,
@@ -668,7 +668,7 @@ function buildSingleImagePayload(params, overrides = {}) {
668
668
  ...overrides,
669
669
  url: (_nullishCoalesce(overrides.url, () => ( base.url))) || preview || "",
670
670
  altText: _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(overrides.altText, () => ( altText)), () => ( base.altText)), () => ( "")),
671
- blurColor: _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(overrides.blurColor, () => ( blurColor)), () => ( base.blurColor)), () => ( _chunk34L4TEE3cjs.DEFAULT_BLUR_COLOR)),
671
+ blurColor: _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(overrides.blurColor, () => ( blurColor)), () => ( base.blurColor)), () => ( _chunkNEDBIIE3cjs.DEFAULT_BLUR_COLOR)),
672
672
  blurDataUrl: _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(overrides.blurDataUrl, () => ( base.blurDataUrl)), () => ( blurDataUrlState)), () => ( ""))
673
673
  };
674
674
  }
@@ -690,11 +690,11 @@ function serializeSingleFormValue(params) {
690
690
  const payload = currentImageData ? {
691
691
  ...currentImageData,
692
692
  altText: altText || currentImageData.altText || "",
693
- blurColor: blurColor || currentImageData.blurColor || _chunk34L4TEE3cjs.DEFAULT_BLUR_COLOR
693
+ blurColor: blurColor || currentImageData.blurColor || _chunkNEDBIIE3cjs.DEFAULT_BLUR_COLOR
694
694
  } : {
695
695
  url: resolvedUrl,
696
696
  altText,
697
- blurColor: blurColor || _chunk34L4TEE3cjs.DEFAULT_BLUR_COLOR,
697
+ blurColor: blurColor || _chunkNEDBIIE3cjs.DEFAULT_BLUR_COLOR,
698
698
  blurDataUrl: blurDataUrlState
699
699
  };
700
700
  return JSON.stringify(payload);
@@ -1099,7 +1099,7 @@ function useImageUpload({
1099
1099
  if (!isMountedRef.current || controller.signal.aborted) return;
1100
1100
  const clamped = Math.max(entry.progress, Math.min(maxCap, nextPct));
1101
1101
  entry.progress = clamped;
1102
- const msg = _chunkDFCSN3X7cjs.getStatusMessage.call(void 0, clamped, uploadLocale);
1102
+ const msg = _chunkKJVYWKIGcjs.getStatusMessage.call(void 0, clamped, uploadLocale);
1103
1103
  entry.message = msg;
1104
1104
  setProgress(clamped);
1105
1105
  setUploadMessage(msg);
@@ -1145,7 +1145,7 @@ function useImageUpload({
1145
1145
  if (!isMountedRef.current || controller.signal.aborted) return null;
1146
1146
  entry.progress = 100;
1147
1147
  setProgress(100);
1148
- const successMsg = _chunkDFCSN3X7cjs.createSuccessMessage.call(void 0, originalSize, data.size, false, uploadLocale);
1148
+ const successMsg = _chunkKJVYWKIGcjs.createSuccessMessage.call(void 0, originalSize, data.size, false, uploadLocale);
1149
1149
  setUploadMessage(successMsg);
1150
1150
  _optionalChain([onProgress, 'optionalCall', _49 => _49(100, successMsg, file, uploadId)]);
1151
1151
  safeSetTimeout(() => {
@@ -1235,14 +1235,14 @@ function useSingleImageState(props) {
1235
1235
  const locale = normalizeUploadLocale(propLocale || ctx.locale);
1236
1236
  const ui = resolveTranslations(locale, translations || ctx.translations);
1237
1237
  const requireAltText = _nullishCoalesce(propRequireAltText, () => ( ctx.requireAltText));
1238
- const standardPreset = preset ? _chunk34L4TEE3cjs.STANDARD_PRESETS[preset] : void 0;
1238
+ const standardPreset = preset ? _chunkNEDBIIE3cjs.STANDARD_PRESETS[preset] : void 0;
1239
1239
  const maxSizeMB = _nullishCoalesce(_nullishCoalesce(propMaxSizeMB, () => ( _optionalChain([standardPreset, 'optionalAccess', _52 => _52.maxSizeMB]))), () => ( 10));
1240
1240
  const requiresManualCommit = Boolean(isOpen);
1241
1241
  const cache = _react.useMemo.call(void 0, () => createUploadSessionCache(ctx.storageKeyPrefix || "iuk"), [ctx.storageKeyPrefix]);
1242
1242
  const objVal = typeof value === "object" && value ? value : null;
1243
1243
  const initPreview = typeof value === "string" ? value : _optionalChain([objVal, 'optionalAccess', _53 => _53.url]) || null;
1244
1244
  const initAlt = _optionalChain([objVal, 'optionalAccess', _54 => _54.altText]) || propInitialAltText || "";
1245
- const initColor = _optionalChain([objVal, 'optionalAccess', _55 => _55.blurColor]) || _chunk34L4TEE3cjs.DEFAULT_BLUR_COLOR;
1245
+ const initColor = _optionalChain([objVal, 'optionalAccess', _55 => _55.blurColor]) || _chunkNEDBIIE3cjs.DEFAULT_BLUR_COLOR;
1246
1246
  const [preview, setPreview] = _react.useState.call(void 0, initPreview);
1247
1247
  const previewRef = _react.useRef.call(void 0, initPreview);
1248
1248
  previewRef.current = preview;
@@ -1266,8 +1266,8 @@ function useSingleImageState(props) {
1266
1266
  const resetColorAndErrorState = () => {
1267
1267
  setValidationError("");
1268
1268
  setHasColorOverride(false);
1269
- setBlurColor(_chunk34L4TEE3cjs.DEFAULT_BLUR_COLOR);
1270
- setDetectedBlurColor(_chunk34L4TEE3cjs.DEFAULT_BLUR_COLOR);
1269
+ setBlurColor(_chunkNEDBIIE3cjs.DEFAULT_BLUR_COLOR);
1270
+ setDetectedBlurColor(_chunkNEDBIIE3cjs.DEFAULT_BLUR_COLOR);
1271
1271
  setIsBlurModalOpen(false);
1272
1272
  };
1273
1273
  const { createPreview, revokePreview } = useFilePreview({ errorLabel: ui.failedCreatePreview });
@@ -1279,7 +1279,7 @@ function useSingleImageState(props) {
1279
1279
  outputFormat,
1280
1280
  maxDimensions,
1281
1281
  customFilename,
1282
- quality: _chunkDFCSN3X7cjs.QUALITY_PRESETS[qualityLevel].value,
1282
+ quality: _chunkKJVYWKIGcjs.QUALITY_PRESETS[qualityLevel].value,
1283
1283
  endpoint,
1284
1284
  uploader,
1285
1285
  headers,
@@ -1290,7 +1290,7 @@ function useSingleImageState(props) {
1290
1290
  if (previewRef.current && previewRef.current !== data.url) revokePreview(previewRef.current);
1291
1291
  setPreview(data.url);
1292
1292
  setSizeInfo({ original: data.originalSize || 0, optimized: data.size });
1293
- const normColor = data.blurColor || _chunk34L4TEE3cjs.DEFAULT_BLUR_COLOR;
1293
+ const normColor = data.blurColor || _chunkNEDBIIE3cjs.DEFAULT_BLUR_COLOR;
1294
1294
  setBlurColor(normColor);
1295
1295
  setDetectedBlurColor(normColor);
1296
1296
  setHasColorOverride(false);
@@ -1322,14 +1322,14 @@ function useSingleImageState(props) {
1322
1322
  const rawAlt = _optionalChain([incomingObj, 'optionalAccess', _58 => _58.altText]) || propInitialAltText || "";
1323
1323
  const cachedAlt = cache.readAltMetaFor({ url: incomingObj ? incomingObj.url : nextPreview, contentHash: _nullishCoalesce(_optionalChain([incomingObj, 'optionalAccess', _59 => _59.contentHash]), () => ( null)) });
1324
1324
  const nextAlt = rawAlt.trim() === "" && nextPreview === preview && (lastAltRef.current.trim() !== "" || _optionalChain([cachedAlt, 'optionalAccess', _60 => _60.trim, 'call', _61 => _61()])) ? lastAltRef.current.trim() || cachedAlt || rawAlt : rawAlt;
1325
- const nextColor = _optionalChain([incomingObj, 'optionalAccess', _62 => _62.blurColor]) || _chunk34L4TEE3cjs.DEFAULT_BLUR_COLOR;
1325
+ const nextColor = _optionalChain([incomingObj, 'optionalAccess', _62 => _62.blurColor]) || _chunkNEDBIIE3cjs.DEFAULT_BLUR_COLOR;
1326
1326
  if (stripUrlCacheQuery(nextPreview) !== stripUrlCacheQuery(preview)) setPreview(nextPreview);
1327
1327
  if (nextAlt !== altText && (nextPreview !== preview || nextAlt.trim() !== "" || !altText.trim())) {
1328
1328
  setAltText(nextAlt);
1329
1329
  lastAltRef.current = nextAlt;
1330
1330
  }
1331
- const nextIsFallback = nextColor === _chunk34L4TEE3cjs.DEFAULT_BLUR_COLOR;
1332
- if (nextColor !== blurColor && (nextPreview !== preview || !hasColorOverride && (!nextIsFallback || blurColor === _chunk34L4TEE3cjs.DEFAULT_BLUR_COLOR))) {
1331
+ const nextIsFallback = nextColor === _chunkNEDBIIE3cjs.DEFAULT_BLUR_COLOR;
1332
+ if (nextColor !== blurColor && (nextPreview !== preview || !hasColorOverride && (!nextIsFallback || blurColor === _chunkNEDBIIE3cjs.DEFAULT_BLUR_COLOR))) {
1333
1333
  setBlurColor(nextColor);
1334
1334
  setDetectedBlurColor(nextColor);
1335
1335
  setHasColorOverride(false);
@@ -1344,7 +1344,7 @@ function useSingleImageState(props) {
1344
1344
  contentHash: _optionalChain([incomingObj, 'optionalAccess', _64 => _64.contentHash]) || _optionalChain([uploadedData, 'optionalAccess', _65 => _65.contentHash])
1345
1345
  });
1346
1346
  if (_optionalChain([cached, 'optionalAccess', _66 => _66.blurDataUrl]) && !nextBlurUrl) setBlurDataUrlState(cached.blurDataUrl);
1347
- if (_optionalChain([cached, 'optionalAccess', _67 => _67.blurColor]) && nextIsFallback && blurColor === _chunk34L4TEE3cjs.DEFAULT_BLUR_COLOR) {
1347
+ if (_optionalChain([cached, 'optionalAccess', _67 => _67.blurColor]) && nextIsFallback && blurColor === _chunkNEDBIIE3cjs.DEFAULT_BLUR_COLOR) {
1348
1348
  setBlurColor(cached.blurColor);
1349
1349
  setDetectedBlurColor(cached.blurColor);
1350
1350
  }
@@ -1370,7 +1370,7 @@ function useSingleImageState(props) {
1370
1370
  }
1371
1371
  };
1372
1372
  const applyBlurColor = (color, options = {}) => {
1373
- const normalized = _chunk34L4TEE3cjs.normalizeColorInput.call(void 0, color);
1373
+ const normalized = _chunkNEDBIIE3cjs.normalizeColorInput.call(void 0, color);
1374
1374
  if (!normalized) return;
1375
1375
  setBlurColor(normalized);
1376
1376
  setHasColorOverride(options.markOverride !== false);
@@ -1387,7 +1387,7 @@ function useSingleImageState(props) {
1387
1387
  abortAll();
1388
1388
  setSelectedFile(file);
1389
1389
  resetColorAndErrorState();
1390
- const err = _chunk34L4TEE3cjs.validateImageFile.call(void 0, file, maxSizeMB, locale);
1390
+ const err = _chunkNEDBIIE3cjs.validateImageFile.call(void 0, file, maxSizeMB, locale);
1391
1391
  if (err) {
1392
1392
  setValidationError(err);
1393
1393
  return;
@@ -1827,7 +1827,7 @@ function useMultiImageState(options) {
1827
1827
  const locale = normalizeUploadLocale(options.locale || ctx.locale);
1828
1828
  const ui = resolveTranslations(locale, options.translations || ctx.translations);
1829
1829
  const requireAltText = _nullishCoalesce(options.requireAltText, () => ( ctx.requireAltText));
1830
- const standardPreset = preset ? _chunk34L4TEE3cjs.STANDARD_PRESETS[preset] : void 0;
1830
+ const standardPreset = preset ? _chunkNEDBIIE3cjs.STANDARD_PRESETS[preset] : void 0;
1831
1831
  const maxSizeMB = _nullishCoalesce(_nullishCoalesce(options.maxSizeMB, () => ( _optionalChain([standardPreset, 'optionalAccess', _124 => _124.maxSizeMB]))), () => ( 10));
1832
1832
  const requiresManualCommit = Boolean(isOpen);
1833
1833
  const [previews, setPreviews] = _react.useState.call(void 0, () => value.map((img) => mapUploadedToPreview(img)));
@@ -1881,7 +1881,7 @@ function useMultiImageState(options) {
1881
1881
  bucket: options.bucket,
1882
1882
  metadata: options.metadata,
1883
1883
  outputFormat: options.outputFormat,
1884
- quality: _chunkDFCSN3X7cjs.QUALITY_PRESETS[qualityLevel].value,
1884
+ quality: _chunkKJVYWKIGcjs.QUALITY_PRESETS[qualityLevel].value,
1885
1885
  maxDimensions: options.maxDimensions,
1886
1886
  customFilename: options.customFilename,
1887
1887
  endpoint: options.endpoint,
@@ -1943,7 +1943,7 @@ function useMultiImageState(options) {
1943
1943
  infoTimeoutRef.current = setTimeout(() => setInfoMessage(""), 5e3);
1944
1944
  }
1945
1945
  const activeCount = previewsRef.current.filter((p) => !p.error).length;
1946
- const validationResult = _chunk34L4TEE3cjs.validateMultipleFiles.call(void 0, imageFiles, maxSizeMB, activeCount, maxImages, locale);
1946
+ const validationResult = _chunkNEDBIIE3cjs.validateMultipleFiles.call(void 0, imageFiles, maxSizeMB, activeCount, maxImages, locale);
1947
1947
  if (validationResult) {
1948
1948
  setValidationError(validationResult);
1949
1949
  return;
@@ -2367,4 +2367,4 @@ function HeadlessMultiUpload(props) {
2367
2367
 
2368
2368
 
2369
2369
  exports.HIDDEN_INPUT_STYLE = HIDDEN_INPUT_STYLE; exports.cx = cx; exports.resolveSlotClass = resolveSlotClass; exports.resolveSlotStyle = resolveSlotStyle; exports.resolveUploadDataState = resolveUploadDataState; exports.arTranslations = arTranslations; exports.enTranslations = enTranslations; exports.DEFAULT_UPLOAD_TRANSLATIONS = DEFAULT_UPLOAD_TRANSLATIONS; exports.ARABIC_UPLOAD_TRANSLATIONS = ARABIC_UPLOAD_TRANSLATIONS; exports.normalizeUploadLocale = normalizeUploadLocale; exports.selectPluralCategory = selectPluralCategory; exports.formatUploadingCount = formatUploadingCount; exports.formatNeedsAltMessage = formatNeedsAltMessage; exports.formatSkippedImagesMessage = formatSkippedImagesMessage; exports.uploadText = uploadText; exports.resolveTranslations = resolveTranslations; exports.ImageUploadProvider = ImageUploadProvider; exports.useImageUploadContext = useImageUploadContext; exports.extractClipboardImageFiles = extractClipboardImageFiles; exports.toFileListLike = toFileListLike; exports.useClipboardPaste = useClipboardPaste; exports.useDragAndDrop = useDragAndDrop; exports.useFilePreview = useFilePreview; exports.createUploadAbortError = createUploadAbortError; exports.isUploadAbortError = isUploadAbortError; exports.parseErrorPayload = parseErrorPayload; exports.buildUploadFormData = buildUploadFormData; exports.uploadViaXhr = uploadViaXhr; exports.useImageUpload = useImageUpload; exports.appendCacheBuster = appendCacheBuster; exports.useSingleImageState = useSingleImageState; exports.useSingleUpload = useSingleUpload; exports.useMultiImageState = useMultiImageState; exports.useMultiUpload = useMultiUpload; exports.HeadlessSingleUpload = HeadlessSingleUpload; exports.HeadlessMultiUpload = HeadlessMultiUpload;
2370
- //# sourceMappingURL=chunk-TA5Y64JM.cjs.map
2370
+ //# sourceMappingURL=chunk-U2TWTEBY.cjs.map