@djangocfg/ui-tools 2.1.335 → 2.1.336

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 (193) hide show
  1. package/README.md +68 -2
  2. package/dist/ChatRoot-IIYQEWUU.mjs +5 -0
  3. package/dist/ChatRoot-IIYQEWUU.mjs.map +1 -0
  4. package/dist/ChatRoot-PNNGQCYF.css +7 -0
  5. package/dist/ChatRoot-PNNGQCYF.css.map +1 -0
  6. package/dist/ChatRoot-UUKTYM4N.cjs +14 -0
  7. package/dist/ChatRoot-UUKTYM4N.cjs.map +1 -0
  8. package/dist/{CronScheduler.client-3O3VU4CI.mjs → CronScheduler.client-DLMXCPAJ.mjs} +4 -4
  9. package/dist/{CronScheduler.client-3O3VU4CI.mjs.map → CronScheduler.client-DLMXCPAJ.mjs.map} +1 -1
  10. package/dist/{CronScheduler.client-A4GO6YBY.cjs → CronScheduler.client-WEJF4PWQ.cjs} +14 -14
  11. package/dist/{CronScheduler.client-A4GO6YBY.cjs.map → CronScheduler.client-WEJF4PWQ.cjs.map} +1 -1
  12. package/dist/{DocsLayout-XLDB6CJ2.cjs → DocsLayout-N5ZJZPBY.cjs} +200 -199
  13. package/dist/DocsLayout-N5ZJZPBY.cjs.map +1 -0
  14. package/dist/{DocsLayout-CTJINVBM.mjs → DocsLayout-VFPPNKSQ.mjs} +7 -6
  15. package/dist/DocsLayout-VFPPNKSQ.mjs.map +1 -0
  16. package/dist/JsonSchemaForm-DD7CLRIG.cjs +13 -0
  17. package/dist/{JsonSchemaForm-6WMS4CIY.cjs.map → JsonSchemaForm-DD7CLRIG.cjs.map} +1 -1
  18. package/dist/JsonSchemaForm-XKUIVELK.mjs +4 -0
  19. package/dist/{JsonSchemaForm-KX4JT3M4.mjs.map → JsonSchemaForm-XKUIVELK.mjs.map} +1 -1
  20. package/dist/JsonTree-55625VVH.mjs +5 -0
  21. package/dist/{JsonTree-F27RMYSI.cjs.map → JsonTree-55625VVH.mjs.map} +1 -1
  22. package/dist/JsonTree-DCM5QGWF.cjs +11 -0
  23. package/dist/{JsonTree-QTJYSHCV.mjs.map → JsonTree-DCM5QGWF.cjs.map} +1 -1
  24. package/dist/{LottiePlayer.client-6WVWDO75.cjs → LottiePlayer.client-2S7ISJ2S.cjs} +6 -6
  25. package/dist/{LottiePlayer.client-6WVWDO75.cjs.map → LottiePlayer.client-2S7ISJ2S.cjs.map} +1 -1
  26. package/dist/{LottiePlayer.client-B4I6WNZM.mjs → LottiePlayer.client-5LDSSJWS.mjs} +4 -4
  27. package/dist/{LottiePlayer.client-B4I6WNZM.mjs.map → LottiePlayer.client-5LDSSJWS.mjs.map} +1 -1
  28. package/dist/{MapContainer-RYG4HPH4.cjs → MapContainer-76YL2JXL.cjs} +8 -8
  29. package/dist/{MapContainer-RYG4HPH4.cjs.map → MapContainer-76YL2JXL.cjs.map} +1 -1
  30. package/dist/{MapContainer-GXQLP5WY.mjs → MapContainer-7HXBI3OH.mjs} +3 -3
  31. package/dist/{MapContainer-GXQLP5WY.mjs.map → MapContainer-7HXBI3OH.mjs.map} +1 -1
  32. package/dist/{Mermaid.client-SXRRI2YW.mjs → Mermaid.client-NL4SVR7F.mjs} +4 -4
  33. package/dist/{Mermaid.client-SXRRI2YW.mjs.map → Mermaid.client-NL4SVR7F.mjs.map} +1 -1
  34. package/dist/{Mermaid.client-W76R5AKJ.cjs → Mermaid.client-NNTI6DFX.cjs} +26 -26
  35. package/dist/{Mermaid.client-W76R5AKJ.cjs.map → Mermaid.client-NNTI6DFX.cjs.map} +1 -1
  36. package/dist/Player-BRV7XTWR.mjs +4 -0
  37. package/dist/{Player-M3GC3VPE.mjs.map → Player-BRV7XTWR.mjs.map} +1 -1
  38. package/dist/Player-PM7F7DD7.cjs +13 -0
  39. package/dist/{Player-ZL2X5LGG.cjs.map → Player-PM7F7DD7.cjs.map} +1 -1
  40. package/dist/{PrettyCode.client-RPDIE5CH.cjs → PrettyCode.client-KOHDVPPN.cjs} +13 -13
  41. package/dist/{PrettyCode.client-RPDIE5CH.cjs.map → PrettyCode.client-KOHDVPPN.cjs.map} +1 -1
  42. package/dist/{PrettyCode.client-SPMTQEG4.mjs → PrettyCode.client-ZGYGKE7G.mjs} +4 -4
  43. package/dist/{PrettyCode.client-SPMTQEG4.mjs.map → PrettyCode.client-ZGYGKE7G.mjs.map} +1 -1
  44. package/dist/TreeRoot-N72OYKXU.cjs +19 -0
  45. package/dist/{TreeRoot-A3J65L6F.mjs.map → TreeRoot-N72OYKXU.cjs.map} +1 -1
  46. package/dist/TreeRoot-VGAIXCUA.mjs +4 -0
  47. package/dist/{TreeRoot-DSK5JILT.cjs.map → TreeRoot-VGAIXCUA.mjs.map} +1 -1
  48. package/dist/chunk-2ZLKZ5VR.mjs +631 -0
  49. package/dist/chunk-2ZLKZ5VR.mjs.map +1 -0
  50. package/dist/{chunk-LFWQ36LJ.mjs → chunk-5G5YBFS6.mjs} +4 -4
  51. package/dist/{chunk-LFWQ36LJ.mjs.map → chunk-5G5YBFS6.mjs.map} +1 -1
  52. package/dist/{chunk-IHAY6FO6.cjs → chunk-5I5QNGUG.cjs} +17 -17
  53. package/dist/{chunk-IHAY6FO6.cjs.map → chunk-5I5QNGUG.cjs.map} +1 -1
  54. package/dist/{chunk-F2CMIIOH.cjs → chunk-76NNDZH6.cjs} +42 -42
  55. package/dist/{chunk-F2CMIIOH.cjs.map → chunk-76NNDZH6.cjs.map} +1 -1
  56. package/dist/chunk-B5AWZOHJ.cjs +649 -0
  57. package/dist/chunk-B5AWZOHJ.cjs.map +1 -0
  58. package/dist/{chunk-KR6B3LVY.mjs → chunk-B6IR5KSC.mjs} +3 -3
  59. package/dist/{chunk-KR6B3LVY.mjs.map → chunk-B6IR5KSC.mjs.map} +1 -1
  60. package/dist/{chunk-5LBDYFWH.mjs → chunk-C6GXVH5J.mjs} +3 -3
  61. package/dist/{chunk-5LBDYFWH.mjs.map → chunk-C6GXVH5J.mjs.map} +1 -1
  62. package/dist/{chunk-NRKD4F5X.cjs → chunk-FEN5S772.cjs} +36 -36
  63. package/dist/{chunk-NRKD4F5X.cjs.map → chunk-FEN5S772.cjs.map} +1 -1
  64. package/dist/{chunk-2SMCH62O.cjs → chunk-FP2RLYQZ.cjs} +11 -11
  65. package/dist/{chunk-2SMCH62O.cjs.map → chunk-FP2RLYQZ.cjs.map} +1 -1
  66. package/dist/{chunk-MOME6KYD.mjs → chunk-G5IEC7SR.mjs} +3 -3
  67. package/dist/{chunk-MOME6KYD.mjs.map → chunk-G5IEC7SR.mjs.map} +1 -1
  68. package/dist/{chunk-SE5IERVH.mjs → chunk-GYIO7W7M.mjs} +3 -3
  69. package/dist/{chunk-SE5IERVH.mjs.map → chunk-GYIO7W7M.mjs.map} +1 -1
  70. package/dist/{chunk-3Z3A7FHA.cjs → chunk-IEEAENLX.cjs} +48 -48
  71. package/dist/{chunk-3Z3A7FHA.cjs.map → chunk-IEEAENLX.cjs.map} +1 -1
  72. package/dist/{chunk-DFTVB66S.cjs → chunk-KNDLV4PI.cjs} +85 -85
  73. package/dist/{chunk-DFTVB66S.cjs.map → chunk-KNDLV4PI.cjs.map} +1 -1
  74. package/dist/{chunk-SSUOENAZ.mjs → chunk-KNEQRUBA.mjs} +3 -3
  75. package/dist/{chunk-SSUOENAZ.mjs.map → chunk-KNEQRUBA.mjs.map} +1 -1
  76. package/dist/chunk-KRETIZU6.mjs +2218 -0
  77. package/dist/chunk-KRETIZU6.mjs.map +1 -0
  78. package/dist/{chunk-CGILA3WO.mjs → chunk-N2XQF2OL.mjs} +5 -3
  79. package/dist/{chunk-CGILA3WO.mjs.map → chunk-N2XQF2OL.mjs.map} +1 -1
  80. package/dist/{chunk-EUADAUBQ.mjs → chunk-N4MZYNR4.mjs} +4 -4
  81. package/dist/{chunk-EUADAUBQ.mjs.map → chunk-N4MZYNR4.mjs.map} +1 -1
  82. package/dist/chunk-NRXYYO5V.cjs +2257 -0
  83. package/dist/chunk-NRXYYO5V.cjs.map +1 -0
  84. package/dist/{chunk-GGKGH5PM.mjs → chunk-OBRSGM64.mjs} +4 -4
  85. package/dist/{chunk-GGKGH5PM.mjs.map → chunk-OBRSGM64.mjs.map} +1 -1
  86. package/dist/{chunk-6JTB2X72.mjs → chunk-ODO4GMW7.mjs} +3 -3
  87. package/dist/{chunk-6JTB2X72.mjs.map → chunk-ODO4GMW7.mjs.map} +1 -1
  88. package/dist/{chunk-WGEGR3DF.cjs → chunk-OLISEQHS.cjs} +5 -2
  89. package/dist/{chunk-WGEGR3DF.cjs.map → chunk-OLISEQHS.cjs.map} +1 -1
  90. package/dist/{chunk-PZKAH7WQ.mjs → chunk-PVAX67JG.mjs} +3 -3
  91. package/dist/{chunk-PZKAH7WQ.mjs.map → chunk-PVAX67JG.mjs.map} +1 -1
  92. package/dist/{chunk-PRPG2T2E.cjs → chunk-QJ6GTUCO.cjs} +6 -6
  93. package/dist/{chunk-PRPG2T2E.cjs.map → chunk-QJ6GTUCO.cjs.map} +1 -1
  94. package/dist/chunk-QW4RBGHN.cjs +961 -0
  95. package/dist/chunk-QW4RBGHN.cjs.map +1 -0
  96. package/dist/{chunk-33AMWFBZ.cjs → chunk-SGP7V2UW.cjs} +15 -15
  97. package/dist/{chunk-33AMWFBZ.cjs.map → chunk-SGP7V2UW.cjs.map} +1 -1
  98. package/dist/{chunk-FX2QFYWF.mjs → chunk-VWQ5WOIL.mjs} +3 -3
  99. package/dist/{chunk-FX2QFYWF.mjs.map → chunk-VWQ5WOIL.mjs.map} +1 -1
  100. package/dist/{chunk-ZLQHUZDU.cjs → chunk-YDPDTOSP.cjs} +139 -139
  101. package/dist/{chunk-ZLQHUZDU.cjs.map → chunk-YDPDTOSP.cjs.map} +1 -1
  102. package/dist/{chunk-77HQWEQ6.cjs → chunk-YW5IVWHQ.cjs} +33 -33
  103. package/dist/{chunk-77HQWEQ6.cjs.map → chunk-YW5IVWHQ.cjs.map} +1 -1
  104. package/dist/{chunk-YXBOAGIM.cjs → chunk-YXZ6GU7H.cjs} +7 -7
  105. package/dist/{chunk-YXBOAGIM.cjs.map → chunk-YXZ6GU7H.cjs.map} +1 -1
  106. package/dist/{chunk-62Y65TGK.mjs → chunk-ZUFTH5IR.mjs} +8 -631
  107. package/dist/chunk-ZUFTH5IR.mjs.map +1 -0
  108. package/dist/components-EHOGXATG.cjs +22 -0
  109. package/dist/{components-5UXYNAKR.cjs.map → components-EHOGXATG.cjs.map} +1 -1
  110. package/dist/components-MQ6DR7TX.cjs +26 -0
  111. package/dist/{components-CFXOEVPN.mjs.map → components-MQ6DR7TX.cjs.map} +1 -1
  112. package/dist/components-XRX7QGLB.mjs +5 -0
  113. package/dist/{components-WYEZL5TE.cjs.map → components-XRX7QGLB.mjs.map} +1 -1
  114. package/dist/components-YATKRWLH.mjs +5 -0
  115. package/dist/{components-ZAGG2PBO.mjs.map → components-YATKRWLH.mjs.map} +1 -1
  116. package/dist/file-icon/index.cjs +6 -6
  117. package/dist/file-icon/index.mjs +1 -1
  118. package/dist/index.cjs +735 -215
  119. package/dist/index.cjs.map +1 -1
  120. package/dist/index.d.cts +972 -39
  121. package/dist/index.d.ts +972 -39
  122. package/dist/index.mjs +387 -31
  123. package/dist/index.mjs.map +1 -1
  124. package/dist/tree/index.cjs +38 -38
  125. package/dist/tree/index.d.cts +2 -2
  126. package/dist/tree/index.d.ts +2 -2
  127. package/dist/tree/index.mjs +3 -3
  128. package/package.json +6 -6
  129. package/src/index.ts +5 -0
  130. package/src/stories/index.ts +3 -1
  131. package/src/tools/Chat/Chat.story.tsx +1006 -0
  132. package/src/tools/Chat/README.md +528 -0
  133. package/src/tools/Chat/components/Attachments.tsx +192 -0
  134. package/src/tools/Chat/components/ChatRoot.tsx +201 -0
  135. package/src/tools/Chat/components/Composer.tsx +134 -0
  136. package/src/tools/Chat/components/EmptyState.tsx +47 -0
  137. package/src/tools/Chat/components/ErrorBanner.tsx +47 -0
  138. package/src/tools/Chat/components/JumpToLatest.tsx +30 -0
  139. package/src/tools/Chat/components/MessageActions.tsx +72 -0
  140. package/src/tools/Chat/components/MessageBubble.tsx +228 -0
  141. package/src/tools/Chat/components/MessageList.tsx +82 -0
  142. package/src/tools/Chat/components/Sources.tsx +55 -0
  143. package/src/tools/Chat/components/StreamingIndicator.tsx +29 -0
  144. package/src/tools/Chat/components/ToolCalls.tsx +172 -0
  145. package/src/tools/Chat/components/index.ts +24 -0
  146. package/src/tools/Chat/config.ts +55 -0
  147. package/src/tools/Chat/context/ChatProvider.tsx +122 -0
  148. package/src/tools/Chat/context/index.ts +9 -0
  149. package/src/tools/Chat/core/audio/audioBus.ts +172 -0
  150. package/src/tools/Chat/core/audio/index.ts +8 -0
  151. package/src/tools/Chat/core/audio/preferences.ts +68 -0
  152. package/src/tools/Chat/core/audio/types.ts +49 -0
  153. package/src/tools/Chat/core/ids.ts +16 -0
  154. package/src/tools/Chat/core/index.ts +5 -0
  155. package/src/tools/Chat/core/markdown.ts +56 -0
  156. package/src/tools/Chat/core/payload-dispatch.ts +54 -0
  157. package/src/tools/Chat/core/persona.ts +35 -0
  158. package/src/tools/Chat/core/reducer.ts +335 -0
  159. package/src/tools/Chat/core/transport/http.ts +167 -0
  160. package/src/tools/Chat/core/transport/index.ts +13 -0
  161. package/src/tools/Chat/core/transport/mock.ts +134 -0
  162. package/src/tools/Chat/core/transport/sse.ts +116 -0
  163. package/src/tools/Chat/core/transport/types.ts +24 -0
  164. package/src/tools/Chat/hooks/index.ts +26 -0
  165. package/src/tools/Chat/hooks/useChat.ts +440 -0
  166. package/src/tools/Chat/hooks/useChatAudio.ts +191 -0
  167. package/src/tools/Chat/hooks/useChatComposer.ts +227 -0
  168. package/src/tools/Chat/hooks/useChatHistory.ts +59 -0
  169. package/src/tools/Chat/hooks/useChatLayout.ts +111 -0
  170. package/src/tools/Chat/hooks/useChatLightbox.ts +34 -0
  171. package/src/tools/Chat/hooks/useChatScroll.ts +132 -0
  172. package/src/tools/Chat/index.ts +158 -0
  173. package/src/tools/Chat/lazy.tsx +14 -0
  174. package/src/tools/Chat/types.ts +237 -0
  175. package/src/tools/Chat/utils/collectImageAttachments.ts +13 -0
  176. package/src/tools/Map/README.md +384 -0
  177. package/dist/DocsLayout-CTJINVBM.mjs.map +0 -1
  178. package/dist/DocsLayout-XLDB6CJ2.cjs.map +0 -1
  179. package/dist/JsonSchemaForm-6WMS4CIY.cjs +0 -13
  180. package/dist/JsonSchemaForm-KX4JT3M4.mjs +0 -4
  181. package/dist/JsonTree-F27RMYSI.cjs +0 -11
  182. package/dist/JsonTree-QTJYSHCV.mjs +0 -5
  183. package/dist/Player-M3GC3VPE.mjs +0 -4
  184. package/dist/Player-ZL2X5LGG.cjs +0 -13
  185. package/dist/TreeRoot-A3J65L6F.mjs +0 -4
  186. package/dist/TreeRoot-DSK5JILT.cjs +0 -19
  187. package/dist/chunk-62Y65TGK.mjs.map +0 -1
  188. package/dist/chunk-TKSFZHCG.cjs +0 -1597
  189. package/dist/chunk-TKSFZHCG.cjs.map +0 -1
  190. package/dist/components-5UXYNAKR.cjs +0 -22
  191. package/dist/components-CFXOEVPN.mjs +0 -5
  192. package/dist/components-WYEZL5TE.cjs +0 -26
  193. package/dist/components-ZAGG2PBO.mjs +0 -5
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tools/ImageViewer/utils/constants.ts","../src/tools/ImageViewer/utils/lqip.ts","../src/tools/ImageViewer/utils/debug.ts","../src/tools/ImageViewer/components/ImageToolbar.tsx","../src/tools/ImageViewer/components/ImageInfo.tsx","../src/tools/ImageViewer/hooks/useImageTransform.ts","../src/tools/ImageViewer/hooks/useImageLoading.ts","../src/tools/ImageViewer/components/ImageViewer.tsx"],"names":["__name","createMediaLogger","useAppT","useControls","useMemo","jsxs","jsx","Button","ZoomOut","DropdownMenu","DropdownMenuTrigger","DropdownMenuContent","DropdownMenuItem","ZoomIn","Maximize2","cn","FlipHorizontal","FlipVertical","RotateCw","Fragment","Expand","useImageCache","useState","useEffect","useCallback","useMediaCacheStore","useRef","contentKey","generateContentKey","url","useHotkey","ImageIcon","AlertCircle","Alert","AlertDescription","TransformWrapper","TransformComponent","ChevronLeft","ChevronRight","Dialog","DialogContent","DialogTitle"],"mappings":"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","file":"chunk-IHAY6FO6.cjs","sourcesContent":["/**\n * ImageViewer constants\n */\n\nimport type { ZoomPreset, ImageTransform } from '../types';\n\n// =============================================================================\n// SIZE LIMITS\n// =============================================================================\n\n/** Maximum image size before blocking (50MB) */\nexport const MAX_IMAGE_SIZE = 50 * 1024 * 1024;\n\n/** Image size threshold for warning (10MB) */\nexport const WARNING_IMAGE_SIZE = 10 * 1024 * 1024;\n\n/** Progressive loading threshold - use LQIP for images > 500KB */\nexport const PROGRESSIVE_LOADING_THRESHOLD = 500 * 1024;\n\n// =============================================================================\n// LQIP CONFIGURATION\n// =============================================================================\n\n/** Low-quality placeholder size (32x32) */\nexport const LQIP_SIZE = 32;\n\n/** LQIP JPEG quality */\nexport const LQIP_QUALITY = 0.5;\n\n// =============================================================================\n// ZOOM CONFIGURATION\n// =============================================================================\n\n/** Minimum zoom level */\nexport const MIN_ZOOM = 0.1;\n\n/** Maximum zoom level */\nexport const MAX_ZOOM = 8;\n\n/** Available zoom presets */\nexport const ZOOM_PRESETS: readonly ZoomPreset[] = [\n { label: 'Fit', value: 'fit' },\n { label: '25%', value: 0.25 },\n { label: '50%', value: 0.5 },\n { label: '100%', value: 1 },\n { label: '200%', value: 2 },\n { label: '400%', value: 4 },\n] as const;\n\n// =============================================================================\n// DEFAULT VALUES\n// =============================================================================\n\n/** Default transform state */\nexport const DEFAULT_TRANSFORM: ImageTransform = {\n rotation: 0,\n flipH: false,\n flipV: false,\n};\n","/**\n * LQIP (Low-Quality Image Placeholder) generator\n *\n * Creates a tiny blurred preview image for progressive loading.\n */\n\nimport { LQIP_QUALITY, LQIP_SIZE } from './constants';\n\n/**\n * Create a low-quality image placeholder from source URL\n *\n * @param imageSrc - Full quality image URL\n * @returns Data URL of tiny preview, or null on error\n */\nexport async function createLQIP(imageSrc: string): Promise<string | null> {\n try {\n // Load the full image\n const img = new Image();\n img.crossOrigin = 'anonymous';\n\n await new Promise<void>((resolve, reject) => {\n img.onload = () => resolve();\n img.onerror = () => reject(new Error('Failed to load image for LQIP'));\n img.src = imageSrc;\n });\n\n // Calculate aspect ratio preserving dimensions\n const aspect = img.naturalWidth / img.naturalHeight;\n const width = aspect >= 1 ? LQIP_SIZE : Math.round(LQIP_SIZE * aspect);\n const height = aspect >= 1 ? Math.round(LQIP_SIZE / aspect) : LQIP_SIZE;\n\n // Create canvas for downscaling\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\n // Draw scaled down image\n ctx.drawImage(img, 0, 0, width, height);\n\n // Return as data URL (very small, ~1-2KB)\n return canvas.toDataURL('image/jpeg', LQIP_QUALITY);\n } catch {\n return null;\n }\n}\n","'use client';\n\n/**\n * ImageViewer Debug Logger\n *\n * Uses universal logger with media-specific helpers.\n * Logs go to both console (dev) and zustand store (for Console panel).\n */\n\nimport { createMediaLogger } from '@djangocfg/ui-core/lib';\n\nexport const imageDebug = createMediaLogger('ImageViewer');\n\nexport default imageDebug;\n","'use client';\n\n/**\n * ImageToolbar - Floating toolbar for image controls\n */\n\nimport { useMemo } from 'react';\nimport { ZoomIn, ZoomOut, RotateCw, FlipHorizontal, FlipVertical, Maximize2, Expand } from 'lucide-react';\nimport { useControls } from 'react-zoom-pan-pinch';\nimport { Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@djangocfg/ui-core/components';\nimport { useAppT } from '@djangocfg/i18n';\nimport { cn } from '@djangocfg/ui-core/lib';\nimport { ZOOM_PRESETS } from '../utils';\nimport type { ImageToolbarProps } from '../types';\n\n// =============================================================================\n// COMPONENT\n// =============================================================================\n\nexport function ImageToolbar({\n scale,\n transform,\n onRotate,\n onFlipH,\n onFlipV,\n onZoomPreset,\n onExpand,\n}: ImageToolbarProps) {\n const t = useAppT();\n const { zoomIn, zoomOut, resetTransform } = useControls();\n\n const labels = useMemo(() => ({\n zoomIn: t('tools.image.zoomIn'),\n zoomOut: t('tools.image.zoomOut'),\n fitToView: t('tools.image.fitToView'),\n flipHorizontal: t('tools.image.flipHorizontal'),\n flipVertical: t('tools.image.flipVertical'),\n rotate: t('tools.image.rotate'),\n fullscreen: t('tools.image.fullscreen'),\n }), [t]);\n\n const zoomLabel = useMemo(() => {\n const percent = Math.round(scale * 100);\n return `${percent}%`;\n }, [scale]);\n\n return (\n <div className=\"absolute bottom-4 left-1/2 -translate-x-1/2 z-10 flex items-center gap-0.5 bg-background/90 backdrop-blur-sm border rounded-lg p-1 shadow-lg\">\n {/* Zoom controls */}\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7\"\n onClick={() => zoomOut()}\n title={labels.zoomOut}\n >\n <ZoomOut className=\"h-3.5 w-3.5\" />\n </Button>\n\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 min-w-[52px] font-mono text-xs\">\n {zoomLabel}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"center\" className=\"min-w-[80px]\">\n {ZOOM_PRESETS.map((preset) => (\n <DropdownMenuItem\n key={preset.label}\n onClick={() => onZoomPreset(preset.value)}\n className=\"text-xs justify-center\"\n >\n {preset.label}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7\"\n onClick={() => zoomIn()}\n title={labels.zoomIn}\n >\n <ZoomIn className=\"h-3.5 w-3.5\" />\n </Button>\n\n <div className=\"w-px h-4 bg-border mx-1\" />\n\n {/* Fit to view */}\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7\"\n onClick={() => resetTransform()}\n title={labels.fitToView}\n >\n <Maximize2 className=\"h-3.5 w-3.5\" />\n </Button>\n\n <div className=\"w-px h-4 bg-border mx-1\" />\n\n {/* Transform controls */}\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className={cn('h-7 w-7', transform.flipH && 'bg-accent')}\n onClick={onFlipH}\n title={labels.flipHorizontal}\n >\n <FlipHorizontal className=\"h-3.5 w-3.5\" />\n </Button>\n\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className={cn('h-7 w-7', transform.flipV && 'bg-accent')}\n onClick={onFlipV}\n title={labels.flipVertical}\n >\n <FlipVertical className=\"h-3.5 w-3.5\" />\n </Button>\n\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7\"\n onClick={onRotate}\n title={labels.rotate}\n >\n <RotateCw className=\"h-3.5 w-3.5\" />\n </Button>\n\n {transform.rotation !== 0 && (\n <span className=\"text-[10px] text-muted-foreground font-mono pl-1\">\n {transform.rotation}°\n </span>\n )}\n\n {onExpand && (\n <>\n <div className=\"w-px h-4 bg-border mx-1\" />\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7\"\n onClick={onExpand}\n title={labels.fullscreen}\n >\n <Expand className=\"h-3.5 w-3.5\" />\n </Button>\n </>\n )}\n </div>\n );\n}\n","'use client';\n\n/**\n * ImageInfo - Displays image dimensions badge\n */\n\nimport { useEffect, useState } from 'react';\nimport { useImageCache } from '../../../stores/mediaCache';\nimport type { ImageInfoProps } from '../types';\n\n// =============================================================================\n// COMPONENT\n// =============================================================================\n\nexport function ImageInfo({ src }: ImageInfoProps) {\n const { getDimensions, cacheDimensions } = useImageCache();\n const [dimensions, setDimensions] = useState<{ w: number; h: number } | null>(null);\n\n useEffect(() => {\n // Check cache first\n const cached = getDimensions(src);\n if (cached) {\n setDimensions({ w: cached.width, h: cached.height });\n return;\n }\n\n // Load and cache dimensions\n const img = new Image();\n img.onload = () => {\n const dims = { w: img.naturalWidth, h: img.naturalHeight };\n setDimensions(dims);\n cacheDimensions(src, { width: dims.w, height: dims.h });\n };\n img.src = src;\n }, [src, getDimensions, cacheDimensions]);\n\n if (!dimensions) return null;\n\n return (\n <div className=\"absolute top-3 right-3 z-10 px-2 py-1 bg-background/80 backdrop-blur-sm border rounded text-[10px] text-muted-foreground font-mono\">\n {dimensions.w} × {dimensions.h}\n </div>\n );\n}\n","'use client';\n\n/**\n * useImageTransform - Manages image rotation and flip state\n */\n\nimport { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { DEFAULT_TRANSFORM } from '../utils';\n\nimport type { ImageTransform } from '../types';\n// =============================================================================\n// TYPES\n// =============================================================================\n\nexport interface UseImageTransformOptions {\n /** Reset transform when this key changes */\n resetKey?: string;\n}\n\nexport interface UseImageTransformReturn {\n /** Current transform state */\n transform: ImageTransform;\n /** Rotate 90 degrees clockwise */\n rotate: () => void;\n /** Toggle horizontal flip */\n flipH: () => void;\n /** Toggle vertical flip */\n flipV: () => void;\n /** Reset all transforms */\n reset: () => void;\n /** CSS transform string for applying to image */\n transformStyle: string;\n}\n\n// =============================================================================\n// HOOK\n// =============================================================================\n\nexport function useImageTransform(\n options: UseImageTransformOptions = {}\n): UseImageTransformReturn {\n const { resetKey } = options;\n\n const [transform, setTransform] = useState<ImageTransform>(DEFAULT_TRANSFORM);\n\n // Reset transform when key changes\n useEffect(() => {\n setTransform(DEFAULT_TRANSFORM);\n }, [resetKey]);\n\n const rotate = useCallback(() => {\n setTransform((prev) => ({\n ...prev,\n rotation: (prev.rotation + 90) % 360,\n }));\n }, []);\n\n const flipH = useCallback(() => {\n setTransform((prev) => ({\n ...prev,\n flipH: !prev.flipH,\n }));\n }, []);\n\n const flipV = useCallback(() => {\n setTransform((prev) => ({\n ...prev,\n flipV: !prev.flipV,\n }));\n }, []);\n\n const reset = useCallback(() => {\n setTransform(DEFAULT_TRANSFORM);\n }, []);\n\n // Build CSS transform string\n const transformStyle = useMemo(() => {\n const transforms: string[] = [];\n\n if (transform.rotation !== 0) {\n transforms.push(`rotate(${transform.rotation}deg)`);\n }\n if (transform.flipH) {\n transforms.push('scaleX(-1)');\n }\n if (transform.flipV) {\n transforms.push('scaleY(-1)');\n }\n\n return transforms.join(' ') || 'none';\n }, [transform]);\n\n return {\n transform,\n rotate,\n flipH,\n flipV,\n reset,\n transformStyle,\n };\n}\n","'use client';\n\n/**\n * useImageLoading - Manages image loading state with LQIP\n */\n\nimport { useEffect, useRef, useState } from 'react';\n\nimport { generateContentKey, useMediaCacheStore } from '../../../stores/mediaCache';\nimport {\n createLQIP, imageDebug, MAX_IMAGE_SIZE, PROGRESSIVE_LOADING_THRESHOLD, WARNING_IMAGE_SIZE\n} from '../utils';\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\nexport interface UseImageLoadingOptions {\n /** Image content (ArrayBuffer or string) */\n content: string | ArrayBuffer;\n /** MIME type for blob creation */\n mimeType?: string;\n /**\n * Direct image URL (bypasses content→blob conversion).\n * When provided, content is ignored and URL is used directly.\n */\n src?: string;\n}\n\nexport interface UseImageLoadingReturn {\n /** Blob URL source for the image */\n src: string | null;\n /** Low-quality placeholder URL */\n lqip: string | null;\n /** Whether full image is loaded */\n isFullyLoaded: boolean;\n /** Whether to use progressive loading */\n useProgressiveLoading: boolean;\n /** Error message if any */\n error: string | null;\n /** Content key for caching */\n contentKey: string | null;\n /** Image size in bytes */\n size: number;\n /** Whether content exists */\n hasContent: boolean;\n}\n\n// =============================================================================\n// HOOK\n// =============================================================================\n\nexport function useImageLoading(options: UseImageLoadingOptions): UseImageLoadingReturn {\n const { content, mimeType, src: directSrc } = options;\n\n // Get stable function references from store (not from hook to avoid re-renders)\n const getOrCreateBlobUrl = useMediaCacheStore.getState().getOrCreateBlobUrl;\n const releaseBlobUrl = useMediaCacheStore.getState().releaseBlobUrl;\n\n const [src, setSrc] = useState<string | null>(null);\n const [lqip, setLqip] = useState<string | null>(null);\n const [isFullyLoaded, setIsFullyLoaded] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const contentKeyRef = useRef<string | null>(null);\n const isMountedRef = useRef(true);\n\n // Calculate size and flags\n const size = content ? (typeof content === 'string' ? content.length : content.byteLength) : 0;\n // When directSrc is provided, we have content (the URL itself)\n const hasContent = directSrc ? true : size > 0;\n const useProgressiveLoading = directSrc ? false : size > PROGRESSIVE_LOADING_THRESHOLD;\n\n // Track unmount for cleanup\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n // Release blob URL only on actual unmount\n if (contentKeyRef.current) {\n useMediaCacheStore.getState().releaseBlobUrl(contentKeyRef.current);\n contentKeyRef.current = null;\n }\n };\n }, []);\n\n // Create blob URL with caching and size validation\n useEffect(() => {\n // Reset error state\n setError(null);\n\n // Direct URL mode - use as-is without blob conversion\n if (directSrc) {\n imageDebug.load(directSrc, 'url');\n setSrc(directSrc);\n setIsFullyLoaded(true);\n return;\n }\n\n if (!hasContent) {\n setSrc(null);\n return;\n }\n\n // Size validation - reject oversized images\n if (size > MAX_IMAGE_SIZE) {\n const sizeMB = (size / 1024 / 1024).toFixed(1);\n const errorMsg = `Image too large: ${sizeMB}MB (maximum: 50MB)`;\n imageDebug.error(errorMsg, { size, sizeMB, maxSize: MAX_IMAGE_SIZE });\n setError(errorMsg);\n setSrc(null);\n return;\n }\n\n // Warn about large images\n if (size > WARNING_IMAGE_SIZE) {\n const sizeMB = (size / 1024 / 1024).toFixed(1);\n imageDebug.warn(`Large image: ${sizeMB}MB - may impact performance`);\n }\n\n // Handle string content (data URLs or binary strings)\n if (typeof content === 'string') {\n // Pass through data URLs directly\n if (content.startsWith('data:')) {\n imageDebug.load(content.slice(0, 50) + '...', 'data-url');\n setSrc(content);\n return;\n }\n\n // Convert binary string to ArrayBuffer and use Blob URL\n const encoder = new TextEncoder();\n const buffer = encoder.encode(content).buffer;\n const contentKey = generateContentKey(buffer);\n\n // Release previous blob URL if content changed\n if (contentKeyRef.current && contentKeyRef.current !== contentKey) {\n releaseBlobUrl(contentKeyRef.current);\n }\n\n contentKeyRef.current = contentKey;\n const url = getOrCreateBlobUrl(contentKey, buffer, mimeType || 'image/png');\n imageDebug.load(url, 'blob');\n imageDebug.state('loaded', { size, mimeType, contentKey });\n setSrc(url);\n return;\n }\n\n // Handle ArrayBuffer with cached blob URL\n const contentKey = generateContentKey(content);\n\n // Release previous blob URL if content changed\n if (contentKeyRef.current && contentKeyRef.current !== contentKey) {\n releaseBlobUrl(contentKeyRef.current);\n }\n\n contentKeyRef.current = contentKey;\n const url = getOrCreateBlobUrl(contentKey, content, mimeType || 'image/png');\n imageDebug.load(url, 'blob');\n imageDebug.state('loaded', { size, mimeType, contentKey });\n setSrc(url);\n\n // No cleanup here - cleanup happens in unmount effect above\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [content, mimeType, hasContent, size, directSrc]);\n\n // Create LQIP for progressive loading\n useEffect(() => {\n if (!src || !useProgressiveLoading) {\n setLqip(null);\n setIsFullyLoaded(true);\n return;\n }\n\n setIsFullyLoaded(false);\n imageDebug.state('progressive loading', { size });\n\n // Create low-quality placeholder\n createLQIP(src).then((placeholder) => {\n if (placeholder) {\n imageDebug.debug('LQIP created');\n setLqip(placeholder);\n }\n });\n\n // Pre-load full image\n const img = new Image();\n img.onload = () => {\n imageDebug.state('fully loaded');\n setIsFullyLoaded(true);\n };\n img.onerror = () => {\n imageDebug.error('Failed to load full image');\n };\n img.src = src;\n }, [src, useProgressiveLoading, size]);\n\n return {\n src,\n lqip,\n isFullyLoaded,\n useProgressiveLoading,\n error,\n contentKey: contentKeyRef.current,\n size,\n hasContent,\n };\n}\n","'use client';\n\n/**\n * ImageViewer - Image viewer with zoom, pan, rotate, flip, gallery navigation\n *\n * Features:\n * - Zoom with mouse wheel and presets\n * - Pan with drag\n * - Rotate 90°\n * - Flip horizontal/vertical\n * - Fullscreen dialog\n * - Keyboard shortcuts (+/-, 0, r, ←/→ for gallery)\n * - Gallery mode: pass images[] with multiple items\n */\n\nimport { useEffect, useState, useRef, useCallback, useMemo } from 'react';\nimport { ImageIcon, AlertCircle, ChevronLeft, ChevronRight } from 'lucide-react';\nimport { TransformWrapper, TransformComponent, useControls } from 'react-zoom-pan-pinch';\nimport { cn, Dialog, DialogContent, DialogTitle, Alert, AlertDescription } from '@djangocfg/ui-core';\nimport { useAppT } from '@djangocfg/i18n';\nimport { useHotkey } from '@djangocfg/ui-core/hooks';\n\nimport { ImageToolbar } from './ImageToolbar';\nimport { ImageInfo } from './ImageInfo';\nimport { useImageTransform, useImageLoading } from '../hooks';\nimport type { ImageViewerProps, ImageItem } from '../types';\n\n// =============================================================================\n// COMPONENT\n// =============================================================================\n\nexport function ImageViewer({\n images,\n initialIndex = 0,\n inDialog = false,\n}: ImageViewerProps) {\n const t = useAppT();\n\n const [currentIndex, setCurrentIndex] = useState(() =>\n Math.max(0, Math.min(initialIndex, images.length - 1))\n );\n\n // Reset index when initialIndex changes (e.g. opening different image)\n useEffect(() => {\n setCurrentIndex(Math.max(0, Math.min(initialIndex, images.length - 1)));\n }, [initialIndex, images.length]);\n\n const current = images[currentIndex];\n const hasMultiple = images.length > 1;\n\n const [scale, setScale] = useState(1);\n const [dialogOpen, setDialogOpen] = useState(false);\n const [loadError, setLoadError] = useState(false);\n const containerRef = useRef<HTMLDivElement>(null);\n const controlsRef = useRef<ReturnType<typeof useControls> | null>(null);\n\n const labels = useMemo(() => ({\n noImage: t('tools.image.noImage'),\n failedToLoad: t('tools.image.failedToLoad'),\n loading: t('ui.form.loading'),\n }), [t]);\n\n const {\n src,\n lqip,\n isFullyLoaded,\n useProgressiveLoading,\n error,\n hasContent,\n } = useImageLoading({\n content: current?.content ?? '',\n mimeType: current?.file.mimeType,\n src: current?.src,\n });\n\n useEffect(() => { setLoadError(false); }, [src]);\n\n const { transform, rotate, flipH, flipV, transformStyle } = useImageTransform({\n resetKey: current?.file.path ?? '',\n });\n\n const handleZoomPreset = useCallback((value: number | 'fit') => {\n if (!controlsRef.current) return;\n if (value === 'fit') controlsRef.current.resetTransform();\n else controlsRef.current.setTransform(0, 0, value);\n }, []);\n\n const handleExpand = useCallback(() => setDialogOpen(true), []);\n\n const prev = useCallback(() =>\n setCurrentIndex((i) => (i - 1 + images.length) % images.length),\n [images.length]\n );\n\n const next = useCallback(() =>\n setCurrentIndex((i) => (i + 1) % images.length),\n [images.length]\n );\n\n // Keyboard: zoom/rotate (only when container focused)\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (!containerRef.current?.contains(document.activeElement) &&\n document.activeElement !== containerRef.current) return;\n const controls = controlsRef.current;\n if (!controls) return;\n switch (e.key) {\n case '+': case '=': e.preventDefault(); controls.zoomIn(); break;\n case '-': e.preventDefault(); controls.zoomOut(); break;\n case '0': e.preventDefault(); controls.resetTransform(); break;\n case 'r': if (!e.metaKey && !e.ctrlKey) { e.preventDefault(); rotate(); } break;\n }\n };\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [rotate]);\n\n // Keyboard: gallery navigation (global when open)\n useHotkey('ArrowLeft', prev, { enabled: hasMultiple, preventDefault: true });\n useHotkey('ArrowRight', next, { enabled: hasMultiple, preventDefault: true });\n\n if (!current) {\n return (\n <div className=\"flex-1 flex flex-col items-center justify-center gap-2 bg-muted/30\">\n <ImageIcon className=\"w-12 h-12 text-muted-foreground/50\" />\n <p className=\"text-sm text-muted-foreground\">{labels.noImage}</p>\n </div>\n );\n }\n\n if (error || loadError) {\n return (\n <div className=\"flex-1 flex flex-col items-center justify-center gap-3 bg-muted/30 p-4\">\n <AlertCircle className=\"w-12 h-12 text-destructive/70\" />\n <Alert variant=\"destructive\" className=\"max-w-md\">\n <AlertCircle className=\"h-4 w-4\" />\n <AlertDescription>{error || labels.failedToLoad}</AlertDescription>\n </Alert>\n </div>\n );\n }\n\n if (!hasContent) {\n return (\n <div className=\"flex-1 flex flex-col items-center justify-center gap-2 bg-muted/30\">\n <ImageIcon className=\"w-12 h-12 text-muted-foreground/50\" />\n <p className=\"text-sm text-muted-foreground\">{labels.noImage}</p>\n </div>\n );\n }\n\n return (\n <div\n ref={containerRef}\n tabIndex={0}\n className={cn(\n 'flex-1 h-full relative overflow-hidden outline-none',\n 'bg-[length:16px_16px]',\n '[background-color:hsl(var(--muted)/0.2)]',\n '[background-image:linear-gradient(45deg,hsl(var(--muted)/0.4)_25%,transparent_25%),linear-gradient(-45deg,hsl(var(--muted)/0.4)_25%,transparent_25%),linear-gradient(45deg,transparent_75%,hsl(var(--muted)/0.4)_75%),linear-gradient(-45deg,transparent_75%,hsl(var(--muted)/0.4)_75%)]',\n '[background-position:0_0,0_8px,8px_-8px,-8px_0px]'\n )}\n >\n {src && <ImageInfo src={src} />}\n\n {useProgressiveLoading && !isFullyLoaded && (\n <div className=\"absolute top-3 left-3 z-10 px-2 py-1 bg-background/80 backdrop-blur-sm border rounded text-[10px] text-muted-foreground font-mono flex items-center gap-1.5\">\n <div className=\"w-2 h-2 bg-blue-500 rounded-full animate-pulse\" />\n {labels.loading}\n </div>\n )}\n\n <TransformWrapper\n initialScale={1}\n minScale={0.1}\n maxScale={8}\n centerOnInit\n centerZoomedOut\n onTransformed={(ref, state) => { setScale(state.scale); controlsRef.current = ref; }}\n onInit={(ref) => { controlsRef.current = ref; }}\n wheel={{ step: 0.1 }}\n doubleClick={{ mode: 'toggle', step: 2 }}\n panning={{ velocityDisabled: false }}\n >\n <ImageToolbar\n scale={scale}\n transform={transform}\n onRotate={rotate}\n onFlipH={flipH}\n onFlipV={flipV}\n onZoomPreset={handleZoomPreset}\n onExpand={!inDialog ? handleExpand : undefined}\n />\n\n <TransformComponent\n wrapperClass=\"!w-full !h-full cursor-grab active:cursor-grabbing\"\n contentClass=\"!w-full !h-full flex items-center justify-center\"\n >\n <div className=\"relative\">\n {useProgressiveLoading && lqip && !isFullyLoaded && (\n <img\n src={lqip}\n alt=\"\"\n aria-hidden=\"true\"\n className=\"absolute inset-0 max-w-full max-h-full object-contain select-none\"\n style={{ transform: transformStyle, filter: 'blur(20px)', transition: 'opacity 0.3s ease-out', opacity: isFullyLoaded ? 0 : 1 }}\n draggable={false}\n />\n )}\n {src && (\n <img\n src={src}\n alt={current.file.name}\n className=\"max-w-full max-h-full object-contain select-none\"\n style={{\n transform: transformStyle,\n transition: useProgressiveLoading ? 'transform 0.15s ease-out, opacity 0.3s ease-out' : 'transform 0.15s ease-out',\n opacity: useProgressiveLoading && !isFullyLoaded ? 0 : 1,\n }}\n draggable={false}\n crossOrigin=\"anonymous\"\n onError={() => setLoadError(true)}\n />\n )}\n </div>\n </TransformComponent>\n </TransformWrapper>\n\n {/* Gallery navigation */}\n {hasMultiple && (\n <>\n <button\n type=\"button\"\n onClick={prev}\n className=\"absolute left-2 top-1/2 -translate-y-1/2 z-10 bg-black/50 hover:bg-black/70 text-white rounded-full p-1.5 transition-colors\"\n >\n <ChevronLeft className=\"h-5 w-5\" />\n </button>\n <button\n type=\"button\"\n onClick={next}\n className=\"absolute right-2 top-1/2 -translate-y-1/2 z-10 bg-black/50 hover:bg-black/70 text-white rounded-full p-1.5 transition-colors\"\n >\n <ChevronRight className=\"h-5 w-5\" />\n </button>\n <div className=\"absolute bottom-2 left-1/2 -translate-x-1/2 z-10 bg-black/50 text-white text-xs px-2 py-0.5 rounded-full pointer-events-none\">\n {currentIndex + 1} / {images.length}\n </div>\n </>\n )}\n\n {/* Fullscreen dialog */}\n {!inDialog && (\n <Dialog open={dialogOpen} onOpenChange={setDialogOpen}>\n <DialogContent className=\"max-w-[95vw] max-h-[95vh] w-[95vw] h-[95vh] p-0 overflow-hidden [&>button]:hidden flex flex-col\">\n <DialogTitle className=\"sr-only\">{current.file.name}</DialogTitle>\n <div className=\"flex items-center justify-between px-4 py-2 border-b shrink-0\">\n <span className=\"text-sm font-medium truncate\">{current.file.name}</span>\n </div>\n <div className=\"flex-1 min-h-0\">\n <ImageViewer images={images} initialIndex={currentIndex} inDialog />\n </div>\n </DialogContent>\n </Dialog>\n )}\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/tools/ImageViewer/utils/constants.ts","../src/tools/ImageViewer/utils/lqip.ts","../src/tools/ImageViewer/utils/debug.ts","../src/tools/ImageViewer/components/ImageToolbar.tsx","../src/tools/ImageViewer/components/ImageInfo.tsx","../src/tools/ImageViewer/hooks/useImageTransform.ts","../src/tools/ImageViewer/hooks/useImageLoading.ts","../src/tools/ImageViewer/components/ImageViewer.tsx"],"names":["__name","createMediaLogger","useAppT","useControls","useMemo","jsxs","jsx","Button","ZoomOut","DropdownMenu","DropdownMenuTrigger","DropdownMenuContent","DropdownMenuItem","ZoomIn","Maximize2","cn","FlipHorizontal","FlipVertical","RotateCw","Fragment","Expand","useImageCache","useState","useEffect","useCallback","useMediaCacheStore","useRef","contentKey","generateContentKey","url","useHotkey","ImageIcon","AlertCircle","Alert","AlertDescription","TransformWrapper","TransformComponent","ChevronLeft","ChevronRight","Dialog","DialogContent","DialogTitle"],"mappings":"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","file":"chunk-5I5QNGUG.cjs","sourcesContent":["/**\n * ImageViewer constants\n */\n\nimport type { ZoomPreset, ImageTransform } from '../types';\n\n// =============================================================================\n// SIZE LIMITS\n// =============================================================================\n\n/** Maximum image size before blocking (50MB) */\nexport const MAX_IMAGE_SIZE = 50 * 1024 * 1024;\n\n/** Image size threshold for warning (10MB) */\nexport const WARNING_IMAGE_SIZE = 10 * 1024 * 1024;\n\n/** Progressive loading threshold - use LQIP for images > 500KB */\nexport const PROGRESSIVE_LOADING_THRESHOLD = 500 * 1024;\n\n// =============================================================================\n// LQIP CONFIGURATION\n// =============================================================================\n\n/** Low-quality placeholder size (32x32) */\nexport const LQIP_SIZE = 32;\n\n/** LQIP JPEG quality */\nexport const LQIP_QUALITY = 0.5;\n\n// =============================================================================\n// ZOOM CONFIGURATION\n// =============================================================================\n\n/** Minimum zoom level */\nexport const MIN_ZOOM = 0.1;\n\n/** Maximum zoom level */\nexport const MAX_ZOOM = 8;\n\n/** Available zoom presets */\nexport const ZOOM_PRESETS: readonly ZoomPreset[] = [\n { label: 'Fit', value: 'fit' },\n { label: '25%', value: 0.25 },\n { label: '50%', value: 0.5 },\n { label: '100%', value: 1 },\n { label: '200%', value: 2 },\n { label: '400%', value: 4 },\n] as const;\n\n// =============================================================================\n// DEFAULT VALUES\n// =============================================================================\n\n/** Default transform state */\nexport const DEFAULT_TRANSFORM: ImageTransform = {\n rotation: 0,\n flipH: false,\n flipV: false,\n};\n","/**\n * LQIP (Low-Quality Image Placeholder) generator\n *\n * Creates a tiny blurred preview image for progressive loading.\n */\n\nimport { LQIP_QUALITY, LQIP_SIZE } from './constants';\n\n/**\n * Create a low-quality image placeholder from source URL\n *\n * @param imageSrc - Full quality image URL\n * @returns Data URL of tiny preview, or null on error\n */\nexport async function createLQIP(imageSrc: string): Promise<string | null> {\n try {\n // Load the full image\n const img = new Image();\n img.crossOrigin = 'anonymous';\n\n await new Promise<void>((resolve, reject) => {\n img.onload = () => resolve();\n img.onerror = () => reject(new Error('Failed to load image for LQIP'));\n img.src = imageSrc;\n });\n\n // Calculate aspect ratio preserving dimensions\n const aspect = img.naturalWidth / img.naturalHeight;\n const width = aspect >= 1 ? LQIP_SIZE : Math.round(LQIP_SIZE * aspect);\n const height = aspect >= 1 ? Math.round(LQIP_SIZE / aspect) : LQIP_SIZE;\n\n // Create canvas for downscaling\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\n // Draw scaled down image\n ctx.drawImage(img, 0, 0, width, height);\n\n // Return as data URL (very small, ~1-2KB)\n return canvas.toDataURL('image/jpeg', LQIP_QUALITY);\n } catch {\n return null;\n }\n}\n","'use client';\n\n/**\n * ImageViewer Debug Logger\n *\n * Uses universal logger with media-specific helpers.\n * Logs go to both console (dev) and zustand store (for Console panel).\n */\n\nimport { createMediaLogger } from '@djangocfg/ui-core/lib';\n\nexport const imageDebug = createMediaLogger('ImageViewer');\n\nexport default imageDebug;\n","'use client';\n\n/**\n * ImageToolbar - Floating toolbar for image controls\n */\n\nimport { useMemo } from 'react';\nimport { ZoomIn, ZoomOut, RotateCw, FlipHorizontal, FlipVertical, Maximize2, Expand } from 'lucide-react';\nimport { useControls } from 'react-zoom-pan-pinch';\nimport { Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@djangocfg/ui-core/components';\nimport { useAppT } from '@djangocfg/i18n';\nimport { cn } from '@djangocfg/ui-core/lib';\nimport { ZOOM_PRESETS } from '../utils';\nimport type { ImageToolbarProps } from '../types';\n\n// =============================================================================\n// COMPONENT\n// =============================================================================\n\nexport function ImageToolbar({\n scale,\n transform,\n onRotate,\n onFlipH,\n onFlipV,\n onZoomPreset,\n onExpand,\n}: ImageToolbarProps) {\n const t = useAppT();\n const { zoomIn, zoomOut, resetTransform } = useControls();\n\n const labels = useMemo(() => ({\n zoomIn: t('tools.image.zoomIn'),\n zoomOut: t('tools.image.zoomOut'),\n fitToView: t('tools.image.fitToView'),\n flipHorizontal: t('tools.image.flipHorizontal'),\n flipVertical: t('tools.image.flipVertical'),\n rotate: t('tools.image.rotate'),\n fullscreen: t('tools.image.fullscreen'),\n }), [t]);\n\n const zoomLabel = useMemo(() => {\n const percent = Math.round(scale * 100);\n return `${percent}%`;\n }, [scale]);\n\n return (\n <div className=\"absolute bottom-4 left-1/2 -translate-x-1/2 z-10 flex items-center gap-0.5 bg-background/90 backdrop-blur-sm border rounded-lg p-1 shadow-lg\">\n {/* Zoom controls */}\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7\"\n onClick={() => zoomOut()}\n title={labels.zoomOut}\n >\n <ZoomOut className=\"h-3.5 w-3.5\" />\n </Button>\n\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 px-2 min-w-[52px] font-mono text-xs\">\n {zoomLabel}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"center\" className=\"min-w-[80px]\">\n {ZOOM_PRESETS.map((preset) => (\n <DropdownMenuItem\n key={preset.label}\n onClick={() => onZoomPreset(preset.value)}\n className=\"text-xs justify-center\"\n >\n {preset.label}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7\"\n onClick={() => zoomIn()}\n title={labels.zoomIn}\n >\n <ZoomIn className=\"h-3.5 w-3.5\" />\n </Button>\n\n <div className=\"w-px h-4 bg-border mx-1\" />\n\n {/* Fit to view */}\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7\"\n onClick={() => resetTransform()}\n title={labels.fitToView}\n >\n <Maximize2 className=\"h-3.5 w-3.5\" />\n </Button>\n\n <div className=\"w-px h-4 bg-border mx-1\" />\n\n {/* Transform controls */}\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className={cn('h-7 w-7', transform.flipH && 'bg-accent')}\n onClick={onFlipH}\n title={labels.flipHorizontal}\n >\n <FlipHorizontal className=\"h-3.5 w-3.5\" />\n </Button>\n\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className={cn('h-7 w-7', transform.flipV && 'bg-accent')}\n onClick={onFlipV}\n title={labels.flipVertical}\n >\n <FlipVertical className=\"h-3.5 w-3.5\" />\n </Button>\n\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7\"\n onClick={onRotate}\n title={labels.rotate}\n >\n <RotateCw className=\"h-3.5 w-3.5\" />\n </Button>\n\n {transform.rotation !== 0 && (\n <span className=\"text-[10px] text-muted-foreground font-mono pl-1\">\n {transform.rotation}°\n </span>\n )}\n\n {onExpand && (\n <>\n <div className=\"w-px h-4 bg-border mx-1\" />\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7\"\n onClick={onExpand}\n title={labels.fullscreen}\n >\n <Expand className=\"h-3.5 w-3.5\" />\n </Button>\n </>\n )}\n </div>\n );\n}\n","'use client';\n\n/**\n * ImageInfo - Displays image dimensions badge\n */\n\nimport { useEffect, useState } from 'react';\nimport { useImageCache } from '../../../stores/mediaCache';\nimport type { ImageInfoProps } from '../types';\n\n// =============================================================================\n// COMPONENT\n// =============================================================================\n\nexport function ImageInfo({ src }: ImageInfoProps) {\n const { getDimensions, cacheDimensions } = useImageCache();\n const [dimensions, setDimensions] = useState<{ w: number; h: number } | null>(null);\n\n useEffect(() => {\n // Check cache first\n const cached = getDimensions(src);\n if (cached) {\n setDimensions({ w: cached.width, h: cached.height });\n return;\n }\n\n // Load and cache dimensions\n const img = new Image();\n img.onload = () => {\n const dims = { w: img.naturalWidth, h: img.naturalHeight };\n setDimensions(dims);\n cacheDimensions(src, { width: dims.w, height: dims.h });\n };\n img.src = src;\n }, [src, getDimensions, cacheDimensions]);\n\n if (!dimensions) return null;\n\n return (\n <div className=\"absolute top-3 right-3 z-10 px-2 py-1 bg-background/80 backdrop-blur-sm border rounded text-[10px] text-muted-foreground font-mono\">\n {dimensions.w} × {dimensions.h}\n </div>\n );\n}\n","'use client';\n\n/**\n * useImageTransform - Manages image rotation and flip state\n */\n\nimport { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { DEFAULT_TRANSFORM } from '../utils';\n\nimport type { ImageTransform } from '../types';\n// =============================================================================\n// TYPES\n// =============================================================================\n\nexport interface UseImageTransformOptions {\n /** Reset transform when this key changes */\n resetKey?: string;\n}\n\nexport interface UseImageTransformReturn {\n /** Current transform state */\n transform: ImageTransform;\n /** Rotate 90 degrees clockwise */\n rotate: () => void;\n /** Toggle horizontal flip */\n flipH: () => void;\n /** Toggle vertical flip */\n flipV: () => void;\n /** Reset all transforms */\n reset: () => void;\n /** CSS transform string for applying to image */\n transformStyle: string;\n}\n\n// =============================================================================\n// HOOK\n// =============================================================================\n\nexport function useImageTransform(\n options: UseImageTransformOptions = {}\n): UseImageTransformReturn {\n const { resetKey } = options;\n\n const [transform, setTransform] = useState<ImageTransform>(DEFAULT_TRANSFORM);\n\n // Reset transform when key changes\n useEffect(() => {\n setTransform(DEFAULT_TRANSFORM);\n }, [resetKey]);\n\n const rotate = useCallback(() => {\n setTransform((prev) => ({\n ...prev,\n rotation: (prev.rotation + 90) % 360,\n }));\n }, []);\n\n const flipH = useCallback(() => {\n setTransform((prev) => ({\n ...prev,\n flipH: !prev.flipH,\n }));\n }, []);\n\n const flipV = useCallback(() => {\n setTransform((prev) => ({\n ...prev,\n flipV: !prev.flipV,\n }));\n }, []);\n\n const reset = useCallback(() => {\n setTransform(DEFAULT_TRANSFORM);\n }, []);\n\n // Build CSS transform string\n const transformStyle = useMemo(() => {\n const transforms: string[] = [];\n\n if (transform.rotation !== 0) {\n transforms.push(`rotate(${transform.rotation}deg)`);\n }\n if (transform.flipH) {\n transforms.push('scaleX(-1)');\n }\n if (transform.flipV) {\n transforms.push('scaleY(-1)');\n }\n\n return transforms.join(' ') || 'none';\n }, [transform]);\n\n return {\n transform,\n rotate,\n flipH,\n flipV,\n reset,\n transformStyle,\n };\n}\n","'use client';\n\n/**\n * useImageLoading - Manages image loading state with LQIP\n */\n\nimport { useEffect, useRef, useState } from 'react';\n\nimport { generateContentKey, useMediaCacheStore } from '../../../stores/mediaCache';\nimport {\n createLQIP, imageDebug, MAX_IMAGE_SIZE, PROGRESSIVE_LOADING_THRESHOLD, WARNING_IMAGE_SIZE\n} from '../utils';\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\nexport interface UseImageLoadingOptions {\n /** Image content (ArrayBuffer or string) */\n content: string | ArrayBuffer;\n /** MIME type for blob creation */\n mimeType?: string;\n /**\n * Direct image URL (bypasses content→blob conversion).\n * When provided, content is ignored and URL is used directly.\n */\n src?: string;\n}\n\nexport interface UseImageLoadingReturn {\n /** Blob URL source for the image */\n src: string | null;\n /** Low-quality placeholder URL */\n lqip: string | null;\n /** Whether full image is loaded */\n isFullyLoaded: boolean;\n /** Whether to use progressive loading */\n useProgressiveLoading: boolean;\n /** Error message if any */\n error: string | null;\n /** Content key for caching */\n contentKey: string | null;\n /** Image size in bytes */\n size: number;\n /** Whether content exists */\n hasContent: boolean;\n}\n\n// =============================================================================\n// HOOK\n// =============================================================================\n\nexport function useImageLoading(options: UseImageLoadingOptions): UseImageLoadingReturn {\n const { content, mimeType, src: directSrc } = options;\n\n // Get stable function references from store (not from hook to avoid re-renders)\n const getOrCreateBlobUrl = useMediaCacheStore.getState().getOrCreateBlobUrl;\n const releaseBlobUrl = useMediaCacheStore.getState().releaseBlobUrl;\n\n const [src, setSrc] = useState<string | null>(null);\n const [lqip, setLqip] = useState<string | null>(null);\n const [isFullyLoaded, setIsFullyLoaded] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const contentKeyRef = useRef<string | null>(null);\n const isMountedRef = useRef(true);\n\n // Calculate size and flags\n const size = content ? (typeof content === 'string' ? content.length : content.byteLength) : 0;\n // When directSrc is provided, we have content (the URL itself)\n const hasContent = directSrc ? true : size > 0;\n const useProgressiveLoading = directSrc ? false : size > PROGRESSIVE_LOADING_THRESHOLD;\n\n // Track unmount for cleanup\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n // Release blob URL only on actual unmount\n if (contentKeyRef.current) {\n useMediaCacheStore.getState().releaseBlobUrl(contentKeyRef.current);\n contentKeyRef.current = null;\n }\n };\n }, []);\n\n // Create blob URL with caching and size validation\n useEffect(() => {\n // Reset error state\n setError(null);\n\n // Direct URL mode - use as-is without blob conversion\n if (directSrc) {\n imageDebug.load(directSrc, 'url');\n setSrc(directSrc);\n setIsFullyLoaded(true);\n return;\n }\n\n if (!hasContent) {\n setSrc(null);\n return;\n }\n\n // Size validation - reject oversized images\n if (size > MAX_IMAGE_SIZE) {\n const sizeMB = (size / 1024 / 1024).toFixed(1);\n const errorMsg = `Image too large: ${sizeMB}MB (maximum: 50MB)`;\n imageDebug.error(errorMsg, { size, sizeMB, maxSize: MAX_IMAGE_SIZE });\n setError(errorMsg);\n setSrc(null);\n return;\n }\n\n // Warn about large images\n if (size > WARNING_IMAGE_SIZE) {\n const sizeMB = (size / 1024 / 1024).toFixed(1);\n imageDebug.warn(`Large image: ${sizeMB}MB - may impact performance`);\n }\n\n // Handle string content (data URLs or binary strings)\n if (typeof content === 'string') {\n // Pass through data URLs directly\n if (content.startsWith('data:')) {\n imageDebug.load(content.slice(0, 50) + '...', 'data-url');\n setSrc(content);\n return;\n }\n\n // Convert binary string to ArrayBuffer and use Blob URL\n const encoder = new TextEncoder();\n const buffer = encoder.encode(content).buffer;\n const contentKey = generateContentKey(buffer);\n\n // Release previous blob URL if content changed\n if (contentKeyRef.current && contentKeyRef.current !== contentKey) {\n releaseBlobUrl(contentKeyRef.current);\n }\n\n contentKeyRef.current = contentKey;\n const url = getOrCreateBlobUrl(contentKey, buffer, mimeType || 'image/png');\n imageDebug.load(url, 'blob');\n imageDebug.state('loaded', { size, mimeType, contentKey });\n setSrc(url);\n return;\n }\n\n // Handle ArrayBuffer with cached blob URL\n const contentKey = generateContentKey(content);\n\n // Release previous blob URL if content changed\n if (contentKeyRef.current && contentKeyRef.current !== contentKey) {\n releaseBlobUrl(contentKeyRef.current);\n }\n\n contentKeyRef.current = contentKey;\n const url = getOrCreateBlobUrl(contentKey, content, mimeType || 'image/png');\n imageDebug.load(url, 'blob');\n imageDebug.state('loaded', { size, mimeType, contentKey });\n setSrc(url);\n\n // No cleanup here - cleanup happens in unmount effect above\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [content, mimeType, hasContent, size, directSrc]);\n\n // Create LQIP for progressive loading\n useEffect(() => {\n if (!src || !useProgressiveLoading) {\n setLqip(null);\n setIsFullyLoaded(true);\n return;\n }\n\n setIsFullyLoaded(false);\n imageDebug.state('progressive loading', { size });\n\n // Create low-quality placeholder\n createLQIP(src).then((placeholder) => {\n if (placeholder) {\n imageDebug.debug('LQIP created');\n setLqip(placeholder);\n }\n });\n\n // Pre-load full image\n const img = new Image();\n img.onload = () => {\n imageDebug.state('fully loaded');\n setIsFullyLoaded(true);\n };\n img.onerror = () => {\n imageDebug.error('Failed to load full image');\n };\n img.src = src;\n }, [src, useProgressiveLoading, size]);\n\n return {\n src,\n lqip,\n isFullyLoaded,\n useProgressiveLoading,\n error,\n contentKey: contentKeyRef.current,\n size,\n hasContent,\n };\n}\n","'use client';\n\n/**\n * ImageViewer - Image viewer with zoom, pan, rotate, flip, gallery navigation\n *\n * Features:\n * - Zoom with mouse wheel and presets\n * - Pan with drag\n * - Rotate 90°\n * - Flip horizontal/vertical\n * - Fullscreen dialog\n * - Keyboard shortcuts (+/-, 0, r, ←/→ for gallery)\n * - Gallery mode: pass images[] with multiple items\n */\n\nimport { useEffect, useState, useRef, useCallback, useMemo } from 'react';\nimport { ImageIcon, AlertCircle, ChevronLeft, ChevronRight } from 'lucide-react';\nimport { TransformWrapper, TransformComponent, useControls } from 'react-zoom-pan-pinch';\nimport { cn, Dialog, DialogContent, DialogTitle, Alert, AlertDescription } from '@djangocfg/ui-core';\nimport { useAppT } from '@djangocfg/i18n';\nimport { useHotkey } from '@djangocfg/ui-core/hooks';\n\nimport { ImageToolbar } from './ImageToolbar';\nimport { ImageInfo } from './ImageInfo';\nimport { useImageTransform, useImageLoading } from '../hooks';\nimport type { ImageViewerProps, ImageItem } from '../types';\n\n// =============================================================================\n// COMPONENT\n// =============================================================================\n\nexport function ImageViewer({\n images,\n initialIndex = 0,\n inDialog = false,\n}: ImageViewerProps) {\n const t = useAppT();\n\n const [currentIndex, setCurrentIndex] = useState(() =>\n Math.max(0, Math.min(initialIndex, images.length - 1))\n );\n\n // Reset index when initialIndex changes (e.g. opening different image)\n useEffect(() => {\n setCurrentIndex(Math.max(0, Math.min(initialIndex, images.length - 1)));\n }, [initialIndex, images.length]);\n\n const current = images[currentIndex];\n const hasMultiple = images.length > 1;\n\n const [scale, setScale] = useState(1);\n const [dialogOpen, setDialogOpen] = useState(false);\n const [loadError, setLoadError] = useState(false);\n const containerRef = useRef<HTMLDivElement>(null);\n const controlsRef = useRef<ReturnType<typeof useControls> | null>(null);\n\n const labels = useMemo(() => ({\n noImage: t('tools.image.noImage'),\n failedToLoad: t('tools.image.failedToLoad'),\n loading: t('ui.form.loading'),\n }), [t]);\n\n const {\n src,\n lqip,\n isFullyLoaded,\n useProgressiveLoading,\n error,\n hasContent,\n } = useImageLoading({\n content: current?.content ?? '',\n mimeType: current?.file.mimeType,\n src: current?.src,\n });\n\n useEffect(() => { setLoadError(false); }, [src]);\n\n const { transform, rotate, flipH, flipV, transformStyle } = useImageTransform({\n resetKey: current?.file.path ?? '',\n });\n\n const handleZoomPreset = useCallback((value: number | 'fit') => {\n if (!controlsRef.current) return;\n if (value === 'fit') controlsRef.current.resetTransform();\n else controlsRef.current.setTransform(0, 0, value);\n }, []);\n\n const handleExpand = useCallback(() => setDialogOpen(true), []);\n\n const prev = useCallback(() =>\n setCurrentIndex((i) => (i - 1 + images.length) % images.length),\n [images.length]\n );\n\n const next = useCallback(() =>\n setCurrentIndex((i) => (i + 1) % images.length),\n [images.length]\n );\n\n // Keyboard: zoom/rotate (only when container focused)\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (!containerRef.current?.contains(document.activeElement) &&\n document.activeElement !== containerRef.current) return;\n const controls = controlsRef.current;\n if (!controls) return;\n switch (e.key) {\n case '+': case '=': e.preventDefault(); controls.zoomIn(); break;\n case '-': e.preventDefault(); controls.zoomOut(); break;\n case '0': e.preventDefault(); controls.resetTransform(); break;\n case 'r': if (!e.metaKey && !e.ctrlKey) { e.preventDefault(); rotate(); } break;\n }\n };\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [rotate]);\n\n // Keyboard: gallery navigation (global when open)\n useHotkey('ArrowLeft', prev, { enabled: hasMultiple, preventDefault: true });\n useHotkey('ArrowRight', next, { enabled: hasMultiple, preventDefault: true });\n\n if (!current) {\n return (\n <div className=\"flex-1 flex flex-col items-center justify-center gap-2 bg-muted/30\">\n <ImageIcon className=\"w-12 h-12 text-muted-foreground/50\" />\n <p className=\"text-sm text-muted-foreground\">{labels.noImage}</p>\n </div>\n );\n }\n\n if (error || loadError) {\n return (\n <div className=\"flex-1 flex flex-col items-center justify-center gap-3 bg-muted/30 p-4\">\n <AlertCircle className=\"w-12 h-12 text-destructive/70\" />\n <Alert variant=\"destructive\" className=\"max-w-md\">\n <AlertCircle className=\"h-4 w-4\" />\n <AlertDescription>{error || labels.failedToLoad}</AlertDescription>\n </Alert>\n </div>\n );\n }\n\n if (!hasContent) {\n return (\n <div className=\"flex-1 flex flex-col items-center justify-center gap-2 bg-muted/30\">\n <ImageIcon className=\"w-12 h-12 text-muted-foreground/50\" />\n <p className=\"text-sm text-muted-foreground\">{labels.noImage}</p>\n </div>\n );\n }\n\n return (\n <div\n ref={containerRef}\n tabIndex={0}\n className={cn(\n 'flex-1 h-full relative overflow-hidden outline-none',\n 'bg-[length:16px_16px]',\n '[background-color:hsl(var(--muted)/0.2)]',\n '[background-image:linear-gradient(45deg,hsl(var(--muted)/0.4)_25%,transparent_25%),linear-gradient(-45deg,hsl(var(--muted)/0.4)_25%,transparent_25%),linear-gradient(45deg,transparent_75%,hsl(var(--muted)/0.4)_75%),linear-gradient(-45deg,transparent_75%,hsl(var(--muted)/0.4)_75%)]',\n '[background-position:0_0,0_8px,8px_-8px,-8px_0px]'\n )}\n >\n {src && <ImageInfo src={src} />}\n\n {useProgressiveLoading && !isFullyLoaded && (\n <div className=\"absolute top-3 left-3 z-10 px-2 py-1 bg-background/80 backdrop-blur-sm border rounded text-[10px] text-muted-foreground font-mono flex items-center gap-1.5\">\n <div className=\"w-2 h-2 bg-blue-500 rounded-full animate-pulse\" />\n {labels.loading}\n </div>\n )}\n\n <TransformWrapper\n initialScale={1}\n minScale={0.1}\n maxScale={8}\n centerOnInit\n centerZoomedOut\n onTransformed={(ref, state) => { setScale(state.scale); controlsRef.current = ref; }}\n onInit={(ref) => { controlsRef.current = ref; }}\n wheel={{ step: 0.1 }}\n doubleClick={{ mode: 'toggle', step: 2 }}\n panning={{ velocityDisabled: false }}\n >\n <ImageToolbar\n scale={scale}\n transform={transform}\n onRotate={rotate}\n onFlipH={flipH}\n onFlipV={flipV}\n onZoomPreset={handleZoomPreset}\n onExpand={!inDialog ? handleExpand : undefined}\n />\n\n <TransformComponent\n wrapperClass=\"!w-full !h-full cursor-grab active:cursor-grabbing\"\n contentClass=\"!w-full !h-full flex items-center justify-center\"\n >\n <div className=\"relative\">\n {useProgressiveLoading && lqip && !isFullyLoaded && (\n <img\n src={lqip}\n alt=\"\"\n aria-hidden=\"true\"\n className=\"absolute inset-0 max-w-full max-h-full object-contain select-none\"\n style={{ transform: transformStyle, filter: 'blur(20px)', transition: 'opacity 0.3s ease-out', opacity: isFullyLoaded ? 0 : 1 }}\n draggable={false}\n />\n )}\n {src && (\n <img\n src={src}\n alt={current.file.name}\n className=\"max-w-full max-h-full object-contain select-none\"\n style={{\n transform: transformStyle,\n transition: useProgressiveLoading ? 'transform 0.15s ease-out, opacity 0.3s ease-out' : 'transform 0.15s ease-out',\n opacity: useProgressiveLoading && !isFullyLoaded ? 0 : 1,\n }}\n draggable={false}\n crossOrigin=\"anonymous\"\n onError={() => setLoadError(true)}\n />\n )}\n </div>\n </TransformComponent>\n </TransformWrapper>\n\n {/* Gallery navigation */}\n {hasMultiple && (\n <>\n <button\n type=\"button\"\n onClick={prev}\n className=\"absolute left-2 top-1/2 -translate-y-1/2 z-10 bg-black/50 hover:bg-black/70 text-white rounded-full p-1.5 transition-colors\"\n >\n <ChevronLeft className=\"h-5 w-5\" />\n </button>\n <button\n type=\"button\"\n onClick={next}\n className=\"absolute right-2 top-1/2 -translate-y-1/2 z-10 bg-black/50 hover:bg-black/70 text-white rounded-full p-1.5 transition-colors\"\n >\n <ChevronRight className=\"h-5 w-5\" />\n </button>\n <div className=\"absolute bottom-2 left-1/2 -translate-x-1/2 z-10 bg-black/50 text-white text-xs px-2 py-0.5 rounded-full pointer-events-none\">\n {currentIndex + 1} / {images.length}\n </div>\n </>\n )}\n\n {/* Fullscreen dialog */}\n {!inDialog && (\n <Dialog open={dialogOpen} onOpenChange={setDialogOpen}>\n <DialogContent className=\"max-w-[95vw] max-h-[95vh] w-[95vw] h-[95vh] p-0 overflow-hidden [&>button]:hidden flex flex-col\">\n <DialogTitle className=\"sr-only\">{current.file.name}</DialogTitle>\n <div className=\"flex items-center justify-between px-4 py-2 border-b shrink-0\">\n <span className=\"text-sm font-medium truncate\">{current.file.name}</span>\n </div>\n <div className=\"flex-1 min-h-0\">\n <ImageViewer images={images} initialIndex={currentIndex} inDialog />\n </div>\n </DialogContent>\n </Dialog>\n )}\n </div>\n );\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkWGEGR3DF_cjs = require('./chunk-WGEGR3DF.cjs');
3
+ var chunkOLISEQHS_cjs = require('./chunk-OLISEQHS.cjs');
4
4
  var react = require('react');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
  var components = require('@djangocfg/ui-core/components');
@@ -36,7 +36,7 @@ function buildCron(state) {
36
36
  return "0 0 * * *";
37
37
  }
38
38
  }
39
- chunkWGEGR3DF_cjs.__name(buildCron, "buildCron");
39
+ chunkOLISEQHS_cjs.__name(buildCron, "buildCron");
40
40
  function formatNumberList(nums) {
41
41
  if (nums.length === 0) return "";
42
42
  if (nums.length === 1) return nums[0].toString();
@@ -56,7 +56,7 @@ function formatNumberList(nums) {
56
56
  ranges.push(start === end ? `${start}` : `${start}-${end}`);
57
57
  return ranges.join(",");
58
58
  }
59
- chunkWGEGR3DF_cjs.__name(formatNumberList, "formatNumberList");
59
+ chunkOLISEQHS_cjs.__name(formatNumberList, "formatNumberList");
60
60
 
61
61
  // src/tools/CronScheduler/utils/cron-parser.ts
62
62
  function parseCron(cron) {
@@ -88,11 +88,11 @@ function parseCron(cron) {
88
88
  isValid: true
89
89
  };
90
90
  }
91
- chunkWGEGR3DF_cjs.__name(parseCron, "parseCron");
91
+ chunkOLISEQHS_cjs.__name(parseCron, "parseCron");
92
92
  function isSimpleField(part) {
93
93
  return part === "*" || /^\d+$/.test(part);
94
94
  }
95
- chunkWGEGR3DF_cjs.__name(isSimpleField, "isSimpleField");
95
+ chunkOLISEQHS_cjs.__name(isSimpleField, "isSimpleField");
96
96
  function detectScheduleType(minutePart, hourPart, dayOfMonthPart, monthPart, dayOfWeekPart) {
97
97
  let type = "custom";
98
98
  let weekDays = [1, 2, 3, 4, 5];
@@ -111,7 +111,7 @@ function detectScheduleType(minutePart, hourPart, dayOfMonthPart, monthPart, day
111
111
  }
112
112
  return { type, weekDays, monthDays };
113
113
  }
114
- chunkWGEGR3DF_cjs.__name(detectScheduleType, "detectScheduleType");
114
+ chunkOLISEQHS_cjs.__name(detectScheduleType, "detectScheduleType");
115
115
  function isValidCronField(part, min, max) {
116
116
  if (part === "*") return true;
117
117
  if (part.includes("/")) {
@@ -133,14 +133,14 @@ function isValidCronField(part, min, max) {
133
133
  }
134
134
  return false;
135
135
  }
136
- chunkWGEGR3DF_cjs.__name(isValidCronField, "isValidCronField");
136
+ chunkOLISEQHS_cjs.__name(isValidCronField, "isValidCronField");
137
137
  function parseField(part, _min, _max) {
138
138
  if (/^\d+$/.test(part)) {
139
139
  return parseInt(part, 10);
140
140
  }
141
141
  return null;
142
142
  }
143
- chunkWGEGR3DF_cjs.__name(parseField, "parseField");
143
+ chunkOLISEQHS_cjs.__name(parseField, "parseField");
144
144
  function parseWeekDays(part) {
145
145
  const result = [];
146
146
  if (part.includes("-")) {
@@ -160,7 +160,7 @@ function parseWeekDays(part) {
160
160
  }
161
161
  return result.length > 0 ? result : [1, 2, 3, 4, 5];
162
162
  }
163
- chunkWGEGR3DF_cjs.__name(parseWeekDays, "parseWeekDays");
163
+ chunkOLISEQHS_cjs.__name(parseWeekDays, "parseWeekDays");
164
164
  function parseMonthDays(part) {
165
165
  const result = [];
166
166
  if (part.includes("-")) {
@@ -180,7 +180,7 @@ function parseMonthDays(part) {
180
180
  }
181
181
  return result.length > 0 ? result : [1];
182
182
  }
183
- chunkWGEGR3DF_cjs.__name(parseMonthDays, "parseMonthDays");
183
+ chunkOLISEQHS_cjs.__name(parseMonthDays, "parseMonthDays");
184
184
  function isValidCron(cron) {
185
185
  if (!cron || typeof cron !== "string") return false;
186
186
  const parts = cron.trim().split(/\s+/);
@@ -188,7 +188,7 @@ function isValidCron(cron) {
188
188
  const [minutePart, hourPart, dayOfMonthPart, monthPart, dayOfWeekPart] = parts;
189
189
  return isValidCronField(minutePart, 0, 59) && isValidCronField(hourPart, 0, 23) && isValidCronField(dayOfMonthPart, 1, 31) && isValidCronField(monthPart, 1, 12) && isValidCronField(dayOfWeekPart, 0, 6);
190
190
  }
191
- chunkWGEGR3DF_cjs.__name(isValidCron, "isValidCron");
191
+ chunkOLISEQHS_cjs.__name(isValidCron, "isValidCron");
192
192
 
193
193
  // src/tools/CronScheduler/utils/cron-humanize.ts
194
194
  var WEEKDAY_SHORT = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
@@ -243,13 +243,13 @@ function humanizeCron(cron) {
243
243
  }
244
244
  return `Custom schedule`;
245
245
  }
246
- chunkWGEGR3DF_cjs.__name(humanizeCron, "humanizeCron");
246
+ chunkOLISEQHS_cjs.__name(humanizeCron, "humanizeCron");
247
247
  function formatTime(hour, minute) {
248
248
  const h = isNaN(hour) ? 0 : Math.max(0, Math.min(23, hour));
249
249
  const m = isNaN(minute) ? 0 : Math.max(0, Math.min(59, minute));
250
250
  return `${h.toString().padStart(2, "0")}:${m.toString().padStart(2, "0")}`;
251
251
  }
252
- chunkWGEGR3DF_cjs.__name(formatTime, "formatTime");
252
+ chunkOLISEQHS_cjs.__name(formatTime, "formatTime");
253
253
  function parseWeekDays2(part) {
254
254
  const result = [];
255
255
  if (part.includes("-") && !part.includes(",")) {
@@ -278,7 +278,7 @@ function parseWeekDays2(part) {
278
278
  }
279
279
  return result.sort((a, b) => a - b);
280
280
  }
281
- chunkWGEGR3DF_cjs.__name(parseWeekDays2, "parseWeekDays");
281
+ chunkOLISEQHS_cjs.__name(parseWeekDays2, "parseWeekDays");
282
282
  function parseMonthDays2(part) {
283
283
  const result = [];
284
284
  if (part.includes("-") && !part.includes(",")) {
@@ -298,23 +298,23 @@ function parseMonthDays2(part) {
298
298
  }
299
299
  return result.sort((a, b) => a - b);
300
300
  }
301
- chunkWGEGR3DF_cjs.__name(parseMonthDays2, "parseMonthDays");
301
+ chunkOLISEQHS_cjs.__name(parseMonthDays2, "parseMonthDays");
302
302
  function isWeekdays(days) {
303
303
  const sorted = [...days].sort((a, b) => a - b);
304
304
  return sorted.join(",") === "1,2,3,4,5";
305
305
  }
306
- chunkWGEGR3DF_cjs.__name(isWeekdays, "isWeekdays");
306
+ chunkOLISEQHS_cjs.__name(isWeekdays, "isWeekdays");
307
307
  function isWeekend(days) {
308
308
  const sorted = [...days].sort((a, b) => a - b);
309
309
  return sorted.join(",") === "0,6";
310
310
  }
311
- chunkWGEGR3DF_cjs.__name(isWeekend, "isWeekend");
311
+ chunkOLISEQHS_cjs.__name(isWeekend, "isWeekend");
312
312
  function ordinal(n) {
313
313
  const s = ["th", "st", "nd", "rd"];
314
314
  const v = n % 100;
315
315
  return n + (s[(v - 20) % 10] || s[v] || s[0]);
316
316
  }
317
- chunkWGEGR3DF_cjs.__name(ordinal, "ordinal");
317
+ chunkOLISEQHS_cjs.__name(ordinal, "ordinal");
318
318
  var CronSchedulerContext = react.createContext(null);
319
319
  var DEFAULT_STATE = {
320
320
  type: "daily",
@@ -461,7 +461,7 @@ function CronSchedulerProvider({
461
461
  );
462
462
  return /* @__PURE__ */ jsxRuntime.jsx(CronSchedulerContext.Provider, { value: contextValue, children });
463
463
  }
464
- chunkWGEGR3DF_cjs.__name(CronSchedulerProvider, "CronSchedulerProvider");
464
+ chunkOLISEQHS_cjs.__name(CronSchedulerProvider, "CronSchedulerProvider");
465
465
  function useCronSchedulerContext() {
466
466
  const context = react.useContext(CronSchedulerContext);
467
467
  if (!context) {
@@ -471,17 +471,17 @@ function useCronSchedulerContext() {
471
471
  }
472
472
  return context;
473
473
  }
474
- chunkWGEGR3DF_cjs.__name(useCronSchedulerContext, "useCronSchedulerContext");
474
+ chunkOLISEQHS_cjs.__name(useCronSchedulerContext, "useCronSchedulerContext");
475
475
  function useCronType() {
476
476
  const { type, setType } = useCronSchedulerContext();
477
477
  return react.useMemo(() => ({ type, setType }), [type, setType]);
478
478
  }
479
- chunkWGEGR3DF_cjs.__name(useCronType, "useCronType");
479
+ chunkOLISEQHS_cjs.__name(useCronType, "useCronType");
480
480
  function useCronTime() {
481
481
  const { hour, minute, setTime } = useCronSchedulerContext();
482
482
  return react.useMemo(() => ({ hour, minute, setTime }), [hour, minute, setTime]);
483
483
  }
484
- chunkWGEGR3DF_cjs.__name(useCronTime, "useCronTime");
484
+ chunkOLISEQHS_cjs.__name(useCronTime, "useCronTime");
485
485
  function useCronWeekDays() {
486
486
  const { weekDays, toggleWeekDay, setWeekDays } = useCronSchedulerContext();
487
487
  return react.useMemo(
@@ -489,7 +489,7 @@ function useCronWeekDays() {
489
489
  [weekDays, toggleWeekDay, setWeekDays]
490
490
  );
491
491
  }
492
- chunkWGEGR3DF_cjs.__name(useCronWeekDays, "useCronWeekDays");
492
+ chunkOLISEQHS_cjs.__name(useCronWeekDays, "useCronWeekDays");
493
493
  function useCronMonthDays() {
494
494
  const { monthDays, toggleMonthDay, setMonthDays } = useCronSchedulerContext();
495
495
  return react.useMemo(
@@ -497,7 +497,7 @@ function useCronMonthDays() {
497
497
  [monthDays, toggleMonthDay, setMonthDays]
498
498
  );
499
499
  }
500
- chunkWGEGR3DF_cjs.__name(useCronMonthDays, "useCronMonthDays");
500
+ chunkOLISEQHS_cjs.__name(useCronMonthDays, "useCronMonthDays");
501
501
  function useCronCustom() {
502
502
  const { customCron, isValid, setCustomCron } = useCronSchedulerContext();
503
503
  return react.useMemo(
@@ -505,7 +505,7 @@ function useCronCustom() {
505
505
  [customCron, isValid, setCustomCron]
506
506
  );
507
507
  }
508
- chunkWGEGR3DF_cjs.__name(useCronCustom, "useCronCustom");
508
+ chunkOLISEQHS_cjs.__name(useCronCustom, "useCronCustom");
509
509
  function useCronPreview() {
510
510
  const { cronExpression, humanDescription, isValid, initialValue } = useCronSchedulerContext();
511
511
  return react.useMemo(
@@ -513,11 +513,11 @@ function useCronPreview() {
513
513
  [cronExpression, humanDescription, isValid, initialValue]
514
514
  );
515
515
  }
516
- chunkWGEGR3DF_cjs.__name(useCronPreview, "useCronPreview");
516
+ chunkOLISEQHS_cjs.__name(useCronPreview, "useCronPreview");
517
517
  function useCronScheduler() {
518
518
  return useCronSchedulerContext();
519
519
  }
520
- chunkWGEGR3DF_cjs.__name(useCronScheduler, "useCronScheduler");
520
+ chunkOLISEQHS_cjs.__name(useCronScheduler, "useCronScheduler");
521
521
  var SCHEDULE_TYPES = [
522
522
  { value: "daily", label: "Daily" },
523
523
  { value: "weekly", label: "Weekly" },
@@ -559,7 +559,7 @@ function ScheduleTypeSelector({
559
559
  }
560
560
  );
561
561
  }
562
- chunkWGEGR3DF_cjs.__name(ScheduleTypeSelector, "ScheduleTypeSelector");
562
+ chunkOLISEQHS_cjs.__name(ScheduleTypeSelector, "ScheduleTypeSelector");
563
563
  var HOURS = Array.from({ length: 24 }, (_, i) => i);
564
564
  var MINUTES = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55];
565
565
  function TimeSelector({
@@ -571,7 +571,7 @@ function TimeSelector({
571
571
  const is24h = format === "24h";
572
572
  const displayHour = is24h ? hour : hour % 12 || 12;
573
573
  const isPM = hour >= 12;
574
- const handleHourChange = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((value) => {
574
+ const handleHourChange = /* @__PURE__ */ chunkOLISEQHS_cjs.__name((value) => {
575
575
  let newHour = parseInt(value, 10);
576
576
  if (!is24h) {
577
577
  if (isPM && newHour !== 12) newHour += 12;
@@ -579,10 +579,10 @@ function TimeSelector({
579
579
  }
580
580
  setTime(newHour, minute);
581
581
  }, "handleHourChange");
582
- const handleMinuteChange = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((value) => {
582
+ const handleMinuteChange = /* @__PURE__ */ chunkOLISEQHS_cjs.__name((value) => {
583
583
  setTime(hour, parseInt(value, 10));
584
584
  }, "handleMinuteChange");
585
- const handlePeriodChange = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((value) => {
585
+ const handlePeriodChange = /* @__PURE__ */ chunkOLISEQHS_cjs.__name((value) => {
586
586
  const newIsPM = value === "PM";
587
587
  let newHour = hour;
588
588
  if (newIsPM && hour < 12) newHour = hour + 12;
@@ -639,7 +639,7 @@ function TimeSelector({
639
639
  ] })
640
640
  ] });
641
641
  }
642
- chunkWGEGR3DF_cjs.__name(TimeSelector, "TimeSelector");
642
+ chunkOLISEQHS_cjs.__name(TimeSelector, "TimeSelector");
643
643
  var DAYS = [
644
644
  { value: 1, label: "Mon" },
645
645
  { value: 2, label: "Tue" },
@@ -711,7 +711,7 @@ function DayChips({
711
711
  )) })
712
712
  ] });
713
713
  }
714
- chunkWGEGR3DF_cjs.__name(DayChips, "DayChips");
714
+ chunkOLISEQHS_cjs.__name(DayChips, "DayChips");
715
715
  function PresetButton({ label, isActive, onClick, disabled }) {
716
716
  return /* @__PURE__ */ jsxRuntime.jsx(
717
717
  "button",
@@ -730,7 +730,7 @@ function PresetButton({ label, isActive, onClick, disabled }) {
730
730
  }
731
731
  );
732
732
  }
733
- chunkWGEGR3DF_cjs.__name(PresetButton, "PresetButton");
733
+ chunkOLISEQHS_cjs.__name(PresetButton, "PresetButton");
734
734
  Array.from({ length: 31 }, (_, i) => i + 1);
735
735
  var GRID_SIZE = 35;
736
736
  function MonthDayGrid({
@@ -811,7 +811,7 @@ function MonthDayGrid({
811
811
  ] })
812
812
  ] });
813
813
  }
814
- chunkWGEGR3DF_cjs.__name(MonthDayGrid, "MonthDayGrid");
814
+ chunkOLISEQHS_cjs.__name(MonthDayGrid, "MonthDayGrid");
815
815
  function PresetButton2({ label, isActive, onClick, disabled }) {
816
816
  return /* @__PURE__ */ jsxRuntime.jsx(
817
817
  "button",
@@ -830,7 +830,7 @@ function PresetButton2({ label, isActive, onClick, disabled }) {
830
830
  }
831
831
  );
832
832
  }
833
- chunkWGEGR3DF_cjs.__name(PresetButton2, "PresetButton");
833
+ chunkOLISEQHS_cjs.__name(PresetButton2, "PresetButton");
834
834
  function CustomInput({ disabled, className }) {
835
835
  const { customCron, isValid, setCustomCron } = useCronCustom();
836
836
  const [localValue, setLocalValue] = react.useState(customCron);
@@ -839,7 +839,7 @@ function CustomInput({ disabled, className }) {
839
839
  setLocalValue(customCron);
840
840
  setLocalValid(isValid);
841
841
  }, [customCron, isValid]);
842
- const handleChange = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((e) => {
842
+ const handleChange = /* @__PURE__ */ chunkOLISEQHS_cjs.__name((e) => {
843
843
  const value = e.target.value;
844
844
  setLocalValue(value);
845
845
  const valid = isValidCron(value);
@@ -867,7 +867,7 @@ function CustomInput({ disabled, className }) {
867
867
  ] })
868
868
  ] });
869
869
  }
870
- chunkWGEGR3DF_cjs.__name(CustomInput, "CustomInput");
870
+ chunkOLISEQHS_cjs.__name(CustomInput, "CustomInput");
871
871
  function CronCheatsheet({ className }) {
872
872
  return /* @__PURE__ */ jsxRuntime.jsxs(components.Popover, { children: [
873
873
  /* @__PURE__ */ jsxRuntime.jsx(components.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -952,7 +952,7 @@ function CronCheatsheet({ className }) {
952
952
  ] }) })
953
953
  ] });
954
954
  }
955
- chunkWGEGR3DF_cjs.__name(CronCheatsheet, "CronCheatsheet");
955
+ chunkOLISEQHS_cjs.__name(CronCheatsheet, "CronCheatsheet");
956
956
  function SchedulePreview({
957
957
  showCronExpression = true,
958
958
  allowCopy = false,
@@ -1036,7 +1036,7 @@ function SchedulePreview({
1036
1036
  }
1037
1037
  );
1038
1038
  }
1039
- chunkWGEGR3DF_cjs.__name(SchedulePreview, "SchedulePreview");
1039
+ chunkOLISEQHS_cjs.__name(SchedulePreview, "SchedulePreview");
1040
1040
 
1041
1041
  exports.CronSchedulerProvider = CronSchedulerProvider;
1042
1042
  exports.CustomInput = CustomInput;
@@ -1057,5 +1057,5 @@ exports.useCronSchedulerContext = useCronSchedulerContext;
1057
1057
  exports.useCronTime = useCronTime;
1058
1058
  exports.useCronType = useCronType;
1059
1059
  exports.useCronWeekDays = useCronWeekDays;
1060
- //# sourceMappingURL=chunk-F2CMIIOH.cjs.map
1061
- //# sourceMappingURL=chunk-F2CMIIOH.cjs.map
1060
+ //# sourceMappingURL=chunk-76NNDZH6.cjs.map
1061
+ //# sourceMappingURL=chunk-76NNDZH6.cjs.map