@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.
- package/README.md +68 -2
- package/dist/ChatRoot-IIYQEWUU.mjs +5 -0
- package/dist/ChatRoot-IIYQEWUU.mjs.map +1 -0
- package/dist/ChatRoot-PNNGQCYF.css +7 -0
- package/dist/ChatRoot-PNNGQCYF.css.map +1 -0
- package/dist/ChatRoot-UUKTYM4N.cjs +14 -0
- package/dist/ChatRoot-UUKTYM4N.cjs.map +1 -0
- package/dist/{CronScheduler.client-3O3VU4CI.mjs → CronScheduler.client-DLMXCPAJ.mjs} +4 -4
- package/dist/{CronScheduler.client-3O3VU4CI.mjs.map → CronScheduler.client-DLMXCPAJ.mjs.map} +1 -1
- package/dist/{CronScheduler.client-A4GO6YBY.cjs → CronScheduler.client-WEJF4PWQ.cjs} +14 -14
- package/dist/{CronScheduler.client-A4GO6YBY.cjs.map → CronScheduler.client-WEJF4PWQ.cjs.map} +1 -1
- package/dist/{DocsLayout-XLDB6CJ2.cjs → DocsLayout-N5ZJZPBY.cjs} +200 -199
- package/dist/DocsLayout-N5ZJZPBY.cjs.map +1 -0
- package/dist/{DocsLayout-CTJINVBM.mjs → DocsLayout-VFPPNKSQ.mjs} +7 -6
- package/dist/DocsLayout-VFPPNKSQ.mjs.map +1 -0
- package/dist/JsonSchemaForm-DD7CLRIG.cjs +13 -0
- package/dist/{JsonSchemaForm-6WMS4CIY.cjs.map → JsonSchemaForm-DD7CLRIG.cjs.map} +1 -1
- package/dist/JsonSchemaForm-XKUIVELK.mjs +4 -0
- package/dist/{JsonSchemaForm-KX4JT3M4.mjs.map → JsonSchemaForm-XKUIVELK.mjs.map} +1 -1
- package/dist/JsonTree-55625VVH.mjs +5 -0
- package/dist/{JsonTree-F27RMYSI.cjs.map → JsonTree-55625VVH.mjs.map} +1 -1
- package/dist/JsonTree-DCM5QGWF.cjs +11 -0
- package/dist/{JsonTree-QTJYSHCV.mjs.map → JsonTree-DCM5QGWF.cjs.map} +1 -1
- package/dist/{LottiePlayer.client-6WVWDO75.cjs → LottiePlayer.client-2S7ISJ2S.cjs} +6 -6
- package/dist/{LottiePlayer.client-6WVWDO75.cjs.map → LottiePlayer.client-2S7ISJ2S.cjs.map} +1 -1
- package/dist/{LottiePlayer.client-B4I6WNZM.mjs → LottiePlayer.client-5LDSSJWS.mjs} +4 -4
- package/dist/{LottiePlayer.client-B4I6WNZM.mjs.map → LottiePlayer.client-5LDSSJWS.mjs.map} +1 -1
- package/dist/{MapContainer-RYG4HPH4.cjs → MapContainer-76YL2JXL.cjs} +8 -8
- package/dist/{MapContainer-RYG4HPH4.cjs.map → MapContainer-76YL2JXL.cjs.map} +1 -1
- package/dist/{MapContainer-GXQLP5WY.mjs → MapContainer-7HXBI3OH.mjs} +3 -3
- package/dist/{MapContainer-GXQLP5WY.mjs.map → MapContainer-7HXBI3OH.mjs.map} +1 -1
- package/dist/{Mermaid.client-SXRRI2YW.mjs → Mermaid.client-NL4SVR7F.mjs} +4 -4
- package/dist/{Mermaid.client-SXRRI2YW.mjs.map → Mermaid.client-NL4SVR7F.mjs.map} +1 -1
- package/dist/{Mermaid.client-W76R5AKJ.cjs → Mermaid.client-NNTI6DFX.cjs} +26 -26
- package/dist/{Mermaid.client-W76R5AKJ.cjs.map → Mermaid.client-NNTI6DFX.cjs.map} +1 -1
- package/dist/Player-BRV7XTWR.mjs +4 -0
- package/dist/{Player-M3GC3VPE.mjs.map → Player-BRV7XTWR.mjs.map} +1 -1
- package/dist/Player-PM7F7DD7.cjs +13 -0
- package/dist/{Player-ZL2X5LGG.cjs.map → Player-PM7F7DD7.cjs.map} +1 -1
- package/dist/{PrettyCode.client-RPDIE5CH.cjs → PrettyCode.client-KOHDVPPN.cjs} +13 -13
- package/dist/{PrettyCode.client-RPDIE5CH.cjs.map → PrettyCode.client-KOHDVPPN.cjs.map} +1 -1
- package/dist/{PrettyCode.client-SPMTQEG4.mjs → PrettyCode.client-ZGYGKE7G.mjs} +4 -4
- package/dist/{PrettyCode.client-SPMTQEG4.mjs.map → PrettyCode.client-ZGYGKE7G.mjs.map} +1 -1
- package/dist/TreeRoot-N72OYKXU.cjs +19 -0
- package/dist/{TreeRoot-A3J65L6F.mjs.map → TreeRoot-N72OYKXU.cjs.map} +1 -1
- package/dist/TreeRoot-VGAIXCUA.mjs +4 -0
- package/dist/{TreeRoot-DSK5JILT.cjs.map → TreeRoot-VGAIXCUA.mjs.map} +1 -1
- package/dist/chunk-2ZLKZ5VR.mjs +631 -0
- package/dist/chunk-2ZLKZ5VR.mjs.map +1 -0
- package/dist/{chunk-LFWQ36LJ.mjs → chunk-5G5YBFS6.mjs} +4 -4
- package/dist/{chunk-LFWQ36LJ.mjs.map → chunk-5G5YBFS6.mjs.map} +1 -1
- package/dist/{chunk-IHAY6FO6.cjs → chunk-5I5QNGUG.cjs} +17 -17
- package/dist/{chunk-IHAY6FO6.cjs.map → chunk-5I5QNGUG.cjs.map} +1 -1
- package/dist/{chunk-F2CMIIOH.cjs → chunk-76NNDZH6.cjs} +42 -42
- package/dist/{chunk-F2CMIIOH.cjs.map → chunk-76NNDZH6.cjs.map} +1 -1
- package/dist/chunk-B5AWZOHJ.cjs +649 -0
- package/dist/chunk-B5AWZOHJ.cjs.map +1 -0
- package/dist/{chunk-KR6B3LVY.mjs → chunk-B6IR5KSC.mjs} +3 -3
- package/dist/{chunk-KR6B3LVY.mjs.map → chunk-B6IR5KSC.mjs.map} +1 -1
- package/dist/{chunk-5LBDYFWH.mjs → chunk-C6GXVH5J.mjs} +3 -3
- package/dist/{chunk-5LBDYFWH.mjs.map → chunk-C6GXVH5J.mjs.map} +1 -1
- package/dist/{chunk-NRKD4F5X.cjs → chunk-FEN5S772.cjs} +36 -36
- package/dist/{chunk-NRKD4F5X.cjs.map → chunk-FEN5S772.cjs.map} +1 -1
- package/dist/{chunk-2SMCH62O.cjs → chunk-FP2RLYQZ.cjs} +11 -11
- package/dist/{chunk-2SMCH62O.cjs.map → chunk-FP2RLYQZ.cjs.map} +1 -1
- package/dist/{chunk-MOME6KYD.mjs → chunk-G5IEC7SR.mjs} +3 -3
- package/dist/{chunk-MOME6KYD.mjs.map → chunk-G5IEC7SR.mjs.map} +1 -1
- package/dist/{chunk-SE5IERVH.mjs → chunk-GYIO7W7M.mjs} +3 -3
- package/dist/{chunk-SE5IERVH.mjs.map → chunk-GYIO7W7M.mjs.map} +1 -1
- package/dist/{chunk-3Z3A7FHA.cjs → chunk-IEEAENLX.cjs} +48 -48
- package/dist/{chunk-3Z3A7FHA.cjs.map → chunk-IEEAENLX.cjs.map} +1 -1
- package/dist/{chunk-DFTVB66S.cjs → chunk-KNDLV4PI.cjs} +85 -85
- package/dist/{chunk-DFTVB66S.cjs.map → chunk-KNDLV4PI.cjs.map} +1 -1
- package/dist/{chunk-SSUOENAZ.mjs → chunk-KNEQRUBA.mjs} +3 -3
- package/dist/{chunk-SSUOENAZ.mjs.map → chunk-KNEQRUBA.mjs.map} +1 -1
- package/dist/chunk-KRETIZU6.mjs +2218 -0
- package/dist/chunk-KRETIZU6.mjs.map +1 -0
- package/dist/{chunk-CGILA3WO.mjs → chunk-N2XQF2OL.mjs} +5 -3
- package/dist/{chunk-CGILA3WO.mjs.map → chunk-N2XQF2OL.mjs.map} +1 -1
- package/dist/{chunk-EUADAUBQ.mjs → chunk-N4MZYNR4.mjs} +4 -4
- package/dist/{chunk-EUADAUBQ.mjs.map → chunk-N4MZYNR4.mjs.map} +1 -1
- package/dist/chunk-NRXYYO5V.cjs +2257 -0
- package/dist/chunk-NRXYYO5V.cjs.map +1 -0
- package/dist/{chunk-GGKGH5PM.mjs → chunk-OBRSGM64.mjs} +4 -4
- package/dist/{chunk-GGKGH5PM.mjs.map → chunk-OBRSGM64.mjs.map} +1 -1
- package/dist/{chunk-6JTB2X72.mjs → chunk-ODO4GMW7.mjs} +3 -3
- package/dist/{chunk-6JTB2X72.mjs.map → chunk-ODO4GMW7.mjs.map} +1 -1
- package/dist/{chunk-WGEGR3DF.cjs → chunk-OLISEQHS.cjs} +5 -2
- package/dist/{chunk-WGEGR3DF.cjs.map → chunk-OLISEQHS.cjs.map} +1 -1
- package/dist/{chunk-PZKAH7WQ.mjs → chunk-PVAX67JG.mjs} +3 -3
- package/dist/{chunk-PZKAH7WQ.mjs.map → chunk-PVAX67JG.mjs.map} +1 -1
- package/dist/{chunk-PRPG2T2E.cjs → chunk-QJ6GTUCO.cjs} +6 -6
- package/dist/{chunk-PRPG2T2E.cjs.map → chunk-QJ6GTUCO.cjs.map} +1 -1
- package/dist/chunk-QW4RBGHN.cjs +961 -0
- package/dist/chunk-QW4RBGHN.cjs.map +1 -0
- package/dist/{chunk-33AMWFBZ.cjs → chunk-SGP7V2UW.cjs} +15 -15
- package/dist/{chunk-33AMWFBZ.cjs.map → chunk-SGP7V2UW.cjs.map} +1 -1
- package/dist/{chunk-FX2QFYWF.mjs → chunk-VWQ5WOIL.mjs} +3 -3
- package/dist/{chunk-FX2QFYWF.mjs.map → chunk-VWQ5WOIL.mjs.map} +1 -1
- package/dist/{chunk-ZLQHUZDU.cjs → chunk-YDPDTOSP.cjs} +139 -139
- package/dist/{chunk-ZLQHUZDU.cjs.map → chunk-YDPDTOSP.cjs.map} +1 -1
- package/dist/{chunk-77HQWEQ6.cjs → chunk-YW5IVWHQ.cjs} +33 -33
- package/dist/{chunk-77HQWEQ6.cjs.map → chunk-YW5IVWHQ.cjs.map} +1 -1
- package/dist/{chunk-YXBOAGIM.cjs → chunk-YXZ6GU7H.cjs} +7 -7
- package/dist/{chunk-YXBOAGIM.cjs.map → chunk-YXZ6GU7H.cjs.map} +1 -1
- package/dist/{chunk-62Y65TGK.mjs → chunk-ZUFTH5IR.mjs} +8 -631
- package/dist/chunk-ZUFTH5IR.mjs.map +1 -0
- package/dist/components-EHOGXATG.cjs +22 -0
- package/dist/{components-5UXYNAKR.cjs.map → components-EHOGXATG.cjs.map} +1 -1
- package/dist/components-MQ6DR7TX.cjs +26 -0
- package/dist/{components-CFXOEVPN.mjs.map → components-MQ6DR7TX.cjs.map} +1 -1
- package/dist/components-XRX7QGLB.mjs +5 -0
- package/dist/{components-WYEZL5TE.cjs.map → components-XRX7QGLB.mjs.map} +1 -1
- package/dist/components-YATKRWLH.mjs +5 -0
- package/dist/{components-ZAGG2PBO.mjs.map → components-YATKRWLH.mjs.map} +1 -1
- package/dist/file-icon/index.cjs +6 -6
- package/dist/file-icon/index.mjs +1 -1
- package/dist/index.cjs +735 -215
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +972 -39
- package/dist/index.d.ts +972 -39
- package/dist/index.mjs +387 -31
- package/dist/index.mjs.map +1 -1
- package/dist/tree/index.cjs +38 -38
- package/dist/tree/index.d.cts +2 -2
- package/dist/tree/index.d.ts +2 -2
- package/dist/tree/index.mjs +3 -3
- package/package.json +6 -6
- package/src/index.ts +5 -0
- package/src/stories/index.ts +3 -1
- package/src/tools/Chat/Chat.story.tsx +1006 -0
- package/src/tools/Chat/README.md +528 -0
- package/src/tools/Chat/components/Attachments.tsx +192 -0
- package/src/tools/Chat/components/ChatRoot.tsx +201 -0
- package/src/tools/Chat/components/Composer.tsx +134 -0
- package/src/tools/Chat/components/EmptyState.tsx +47 -0
- package/src/tools/Chat/components/ErrorBanner.tsx +47 -0
- package/src/tools/Chat/components/JumpToLatest.tsx +30 -0
- package/src/tools/Chat/components/MessageActions.tsx +72 -0
- package/src/tools/Chat/components/MessageBubble.tsx +228 -0
- package/src/tools/Chat/components/MessageList.tsx +82 -0
- package/src/tools/Chat/components/Sources.tsx +55 -0
- package/src/tools/Chat/components/StreamingIndicator.tsx +29 -0
- package/src/tools/Chat/components/ToolCalls.tsx +172 -0
- package/src/tools/Chat/components/index.ts +24 -0
- package/src/tools/Chat/config.ts +55 -0
- package/src/tools/Chat/context/ChatProvider.tsx +122 -0
- package/src/tools/Chat/context/index.ts +9 -0
- package/src/tools/Chat/core/audio/audioBus.ts +172 -0
- package/src/tools/Chat/core/audio/index.ts +8 -0
- package/src/tools/Chat/core/audio/preferences.ts +68 -0
- package/src/tools/Chat/core/audio/types.ts +49 -0
- package/src/tools/Chat/core/ids.ts +16 -0
- package/src/tools/Chat/core/index.ts +5 -0
- package/src/tools/Chat/core/markdown.ts +56 -0
- package/src/tools/Chat/core/payload-dispatch.ts +54 -0
- package/src/tools/Chat/core/persona.ts +35 -0
- package/src/tools/Chat/core/reducer.ts +335 -0
- package/src/tools/Chat/core/transport/http.ts +167 -0
- package/src/tools/Chat/core/transport/index.ts +13 -0
- package/src/tools/Chat/core/transport/mock.ts +134 -0
- package/src/tools/Chat/core/transport/sse.ts +116 -0
- package/src/tools/Chat/core/transport/types.ts +24 -0
- package/src/tools/Chat/hooks/index.ts +26 -0
- package/src/tools/Chat/hooks/useChat.ts +440 -0
- package/src/tools/Chat/hooks/useChatAudio.ts +191 -0
- package/src/tools/Chat/hooks/useChatComposer.ts +227 -0
- package/src/tools/Chat/hooks/useChatHistory.ts +59 -0
- package/src/tools/Chat/hooks/useChatLayout.ts +111 -0
- package/src/tools/Chat/hooks/useChatLightbox.ts +34 -0
- package/src/tools/Chat/hooks/useChatScroll.ts +132 -0
- package/src/tools/Chat/index.ts +158 -0
- package/src/tools/Chat/lazy.tsx +14 -0
- package/src/tools/Chat/types.ts +237 -0
- package/src/tools/Chat/utils/collectImageAttachments.ts +13 -0
- package/src/tools/Map/README.md +384 -0
- package/dist/DocsLayout-CTJINVBM.mjs.map +0 -1
- package/dist/DocsLayout-XLDB6CJ2.cjs.map +0 -1
- package/dist/JsonSchemaForm-6WMS4CIY.cjs +0 -13
- package/dist/JsonSchemaForm-KX4JT3M4.mjs +0 -4
- package/dist/JsonTree-F27RMYSI.cjs +0 -11
- package/dist/JsonTree-QTJYSHCV.mjs +0 -5
- package/dist/Player-M3GC3VPE.mjs +0 -4
- package/dist/Player-ZL2X5LGG.cjs +0 -13
- package/dist/TreeRoot-A3J65L6F.mjs +0 -4
- package/dist/TreeRoot-DSK5JILT.cjs +0 -19
- package/dist/chunk-62Y65TGK.mjs.map +0 -1
- package/dist/chunk-TKSFZHCG.cjs +0 -1597
- package/dist/chunk-TKSFZHCG.cjs.map +0 -1
- package/dist/components-5UXYNAKR.cjs +0 -22
- package/dist/components-CFXOEVPN.mjs +0 -5
- package/dist/components-WYEZL5TE.cjs +0 -26
- 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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
91
|
+
chunkOLISEQHS_cjs.__name(parseCron, "parseCron");
|
|
92
92
|
function isSimpleField(part) {
|
|
93
93
|
return part === "*" || /^\d+$/.test(part);
|
|
94
94
|
}
|
|
95
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
516
|
+
chunkOLISEQHS_cjs.__name(useCronPreview, "useCronPreview");
|
|
517
517
|
function useCronScheduler() {
|
|
518
518
|
return useCronSchedulerContext();
|
|
519
519
|
}
|
|
520
|
-
|
|
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
|
-
|
|
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__ */
|
|
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__ */
|
|
582
|
+
const handleMinuteChange = /* @__PURE__ */ chunkOLISEQHS_cjs.__name((value) => {
|
|
583
583
|
setTime(hour, parseInt(value, 10));
|
|
584
584
|
}, "handleMinuteChange");
|
|
585
|
-
const handlePeriodChange = /* @__PURE__ */
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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__ */
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
1061
|
-
//# sourceMappingURL=chunk-
|
|
1060
|
+
//# sourceMappingURL=chunk-76NNDZH6.cjs.map
|
|
1061
|
+
//# sourceMappingURL=chunk-76NNDZH6.cjs.map
|