@cannyminds/dms-file-viewers 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/{chunk-PFJKVNUA.mjs → chunk-ZUA4KYTB.mjs} +170 -117
  2. package/dist/chunk-ZUA4KYTB.mjs.map +1 -0
  3. package/dist/{chunk-CQ3HSM5S.js → chunk-ZWEQRVCH.js} +174 -121
  4. package/dist/chunk-ZWEQRVCH.js.map +1 -0
  5. package/dist/components/viewers/AudioViewer.d.mts +1 -1
  6. package/dist/components/viewers/AudioViewer.d.ts +1 -1
  7. package/dist/components/viewers/DefaultViewer.d.mts +1 -1
  8. package/dist/components/viewers/DefaultViewer.d.ts +1 -1
  9. package/dist/components/viewers/ImageViewer.d.mts +1 -1
  10. package/dist/components/viewers/ImageViewer.d.ts +1 -1
  11. package/dist/components/viewers/PDFViewer.d.mts +1 -1
  12. package/dist/components/viewers/PDFViewer.d.ts +1 -1
  13. package/dist/components/viewers/TIFFViewer.d.mts +1 -1
  14. package/dist/components/viewers/TIFFViewer.d.ts +1 -1
  15. package/dist/components/viewers/TIFFViewer.js +2 -2
  16. package/dist/components/viewers/TIFFViewer.mjs +1 -1
  17. package/dist/components/viewers/TextViewer.d.mts +1 -1
  18. package/dist/components/viewers/TextViewer.d.ts +1 -1
  19. package/dist/components/viewers/VideoViewer.d.mts +1 -1
  20. package/dist/components/viewers/VideoViewer.d.ts +1 -1
  21. package/dist/index.d.mts +2 -2
  22. package/dist/index.d.ts +2 -2
  23. package/dist/index.js +10 -8
  24. package/dist/index.js.map +1 -1
  25. package/dist/index.mjs +9 -7
  26. package/dist/index.mjs.map +1 -1
  27. package/dist/{types-BmZB9kkJ.d.mts → types-CQIoF7E1.d.mts} +3 -0
  28. package/dist/{types-BmZB9kkJ.d.ts → types-CQIoF7E1.d.ts} +3 -0
  29. package/package.json +2 -3
  30. package/dist/chunk-CQ3HSM5S.js.map +0 -1
  31. package/dist/chunk-PFJKVNUA.mjs.map +0 -1
@@ -39,40 +39,7 @@ import FitScreenIcon from "@mui/icons-material/FitScreen";
39
39
  import AspectRatioIcon from "@mui/icons-material/AspectRatio";
40
40
  import InfoIcon from "@mui/icons-material/Info";
41
41
  import DescriptionIcon from "@mui/icons-material/Description";
42
- import * as UTIF from "utif";
43
42
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
44
- var decodeTiff = (buffer) => {
45
- if (typeof window === "undefined") {
46
- return [];
47
- }
48
- const frames = [];
49
- const images = UTIF.decode(buffer);
50
- images.forEach((image) => {
51
- try {
52
- UTIF.decodeImage(buffer, image);
53
- const rgba = UTIF.toRGBA8(image);
54
- const width = image.width || 0;
55
- const height = image.height || 0;
56
- if (!width || !height) {
57
- return;
58
- }
59
- const canvas = document.createElement("canvas");
60
- canvas.width = width;
61
- canvas.height = height;
62
- const context = canvas.getContext("2d");
63
- if (!context) {
64
- return;
65
- }
66
- const clamped = new Uint8ClampedArray(rgba.length);
67
- clamped.set(rgba);
68
- const imageData = new ImageData(clamped, width, height);
69
- context.putImageData(imageData, 0, 0);
70
- frames.push({ dataUrl: canvas.toDataURL("image/png"), width, height });
71
- } catch (error) {
72
- }
73
- });
74
- return frames;
75
- };
76
43
  var resolveDocumentName = (file, fileName, url) => {
77
44
  if (file?.name) {
78
45
  return file.name;
@@ -91,6 +58,7 @@ var TIFFViewerContent = ({
91
58
  file,
92
59
  url,
93
60
  fileName,
61
+ totalPages = 1,
94
62
  className = "",
95
63
  style = {},
96
64
  width = "100%",
@@ -101,6 +69,7 @@ var TIFFViewerContent = ({
101
69
  onPrintClick,
102
70
  onMetadataClick,
103
71
  onPropertiesClick,
72
+ pageLoader,
104
73
  showDownload = true,
105
74
  showPrint = true,
106
75
  showMetadata = false,
@@ -121,8 +90,7 @@ var TIFFViewerContent = ({
121
90
  toolbarActions,
122
91
  ...props
123
92
  }) => {
124
- const [frames, setFrames] = useState([]);
125
- const [currentIndex, setCurrentIndex] = useState(0);
93
+ const [currentPage, setCurrentPage] = useState(1);
126
94
  const [isLoading, setIsLoading] = useState(false);
127
95
  const [error, setError] = useState(null);
128
96
  const [fitMode, setFitMode] = useState("fit-page");
@@ -130,8 +98,79 @@ var TIFFViewerContent = ({
130
98
  const [viewportWidth, setViewportWidth] = useState(0);
131
99
  const [viewportHeight, setViewportHeight] = useState(0);
132
100
  const [isFullScreen, setIsFullScreen] = useState(false);
101
+ const [imageUrl, setImageUrl] = useState(null);
102
+ const [pageImages, setPageImages] = useState(/* @__PURE__ */ new Map());
103
+ const [internalLoading, setInternalLoading] = useState(false);
133
104
  const viewportRef = useRef(null);
134
105
  const containerRef = useRef(null);
106
+ const pageLoaderRef = useRef(pageLoader);
107
+ useEffect(() => {
108
+ pageLoaderRef.current = pageLoader;
109
+ }, [pageLoader]);
110
+ const updatePageImage = useCallback((pageData, pageNumber) => {
111
+ const blob = new Blob([pageData]);
112
+ const imageUrl2 = URL.createObjectURL(blob);
113
+ setPageImages((prev) => {
114
+ const oldUrl = prev.get(pageNumber);
115
+ if (oldUrl && oldUrl !== imageUrl2) {
116
+ URL.revokeObjectURL(oldUrl);
117
+ }
118
+ return new Map(prev).set(pageNumber, imageUrl2);
119
+ });
120
+ setCurrentPage(pageNumber);
121
+ setImageUrl(imageUrl2);
122
+ }, []);
123
+ useEffect(() => {
124
+ const loadInitialPage = async () => {
125
+ if (pageLoaderRef.current && !pageImages.has(1) && currentPage === 1) {
126
+ setInternalLoading(true);
127
+ setError(null);
128
+ try {
129
+ const pageData = await pageLoaderRef.current(1);
130
+ if (pageData) {
131
+ updatePageImage(pageData, 1);
132
+ } else {
133
+ setError("Failed to load page 1");
134
+ }
135
+ } catch (err) {
136
+ const message = err instanceof Error ? err.message : "Unable to load page 1";
137
+ setError(message);
138
+ onError?.(new Error(message));
139
+ } finally {
140
+ setInternalLoading(false);
141
+ }
142
+ }
143
+ };
144
+ loadInitialPage();
145
+ }, [pageImages, currentPage, updatePageImage, onError]);
146
+ const handlePageChange = useCallback(async (newPageNumber) => {
147
+ if (!pageLoaderRef.current) {
148
+ console.warn("pageLoader not provided - page navigation disabled");
149
+ return;
150
+ }
151
+ const cachedUrl = pageImages.get(newPageNumber);
152
+ if (cachedUrl) {
153
+ setCurrentPage(newPageNumber);
154
+ setImageUrl(cachedUrl);
155
+ return;
156
+ }
157
+ setInternalLoading(true);
158
+ setError(null);
159
+ try {
160
+ const pageData = await pageLoaderRef.current(newPageNumber);
161
+ if (pageData) {
162
+ updatePageImage(pageData, newPageNumber);
163
+ } else {
164
+ setError(`Failed to load page ${newPageNumber}`);
165
+ }
166
+ } catch (err) {
167
+ const message = err instanceof Error ? err.message : `Unable to load page ${newPageNumber}`;
168
+ setError(message);
169
+ onError?.(new Error(message));
170
+ } finally {
171
+ setInternalLoading(false);
172
+ }
173
+ }, [pageImages, onError, updatePageImage]);
135
174
  const resolvedFileName = useMemo(
136
175
  () => fileName || sourceDescription,
137
176
  [fileName, sourceDescription]
@@ -140,63 +179,74 @@ var TIFFViewerContent = ({
140
179
  () => getFileExtension(resolvedFileName || ""),
141
180
  [resolvedFileName]
142
181
  );
143
- const loadTiff = useCallback(async () => {
182
+ const loadImage = useCallback(async (resetPage = false) => {
144
183
  if (!file && !url) {
145
- setFrames([]);
146
- setCurrentIndex(0);
184
+ setImageUrl(null);
185
+ if (resetPage) setCurrentPage(1);
147
186
  setError(null);
148
187
  return;
149
188
  }
150
- if (typeof window === "undefined") {
151
- return;
152
- }
153
189
  setIsLoading(true);
154
190
  setError(null);
155
191
  try {
156
- let buffer;
192
+ let imageDataUrl;
157
193
  if (file) {
158
- buffer = await file.arrayBuffer();
194
+ imageDataUrl = URL.createObjectURL(file);
195
+ } else if (url) {
196
+ imageDataUrl = url;
159
197
  } else {
160
- const response = await fetch(url);
161
- if (!response.ok) {
162
- throw new Error(`Failed to fetch TIFF (${response.status})`);
163
- }
164
- buffer = await response.arrayBuffer();
198
+ throw new Error("No file or URL provided");
165
199
  }
166
- const decodedFrames = decodeTiff(buffer);
167
- setFrames(decodedFrames);
168
- setCurrentIndex(0);
169
- setFitMode("fit-page");
170
- setZoom(1);
171
- if (decodedFrames.length > 0) {
172
- onLoad?.();
173
- } else {
174
- setError("No displayable frames detected in TIFF file.");
200
+ setImageUrl(imageDataUrl);
201
+ if (resetPage) {
202
+ setCurrentPage(1);
203
+ setFitMode("fit-page");
204
+ setZoom(1);
175
205
  }
206
+ onLoad?.();
176
207
  } catch (err) {
177
- const message = err instanceof Error ? err.message : "Unable to load TIFF file";
208
+ const message = err instanceof Error ? err.message : "Unable to load image file";
178
209
  setError(message);
179
- setFrames([]);
180
- setCurrentIndex(0);
181
- setFitMode("fit-page");
182
- setZoom(1);
210
+ setImageUrl(null);
211
+ if (resetPage) {
212
+ setCurrentPage(1);
213
+ setFitMode("fit-page");
214
+ setZoom(1);
215
+ }
183
216
  onError?.(new Error(message));
184
217
  } finally {
185
218
  setIsLoading(false);
186
219
  }
187
220
  }, [file, url, onLoad, onError]);
221
+ const [previousFileSource, setPreviousFileSource] = useState({});
188
222
  useEffect(() => {
189
- void loadTiff();
190
- }, [loadTiff]);
191
- const currentFrame = frames[currentIndex];
192
- const hasFrames = frames.length > 0;
193
- const hasMultipleFrames = frames.length > 1;
223
+ const currentFileSource = { file, url };
224
+ const isNewFile = previousFileSource.file !== file || previousFileSource.url !== url;
225
+ if (isNewFile) {
226
+ setPreviousFileSource(currentFileSource);
227
+ void loadImage(true);
228
+ } else {
229
+ void loadImage(false);
230
+ }
231
+ }, [file, url, loadImage, previousFileSource.file, previousFileSource.url]);
232
+ useEffect(() => {
233
+ return () => {
234
+ pageImages.forEach((url2) => {
235
+ URL.revokeObjectURL(url2);
236
+ });
237
+ if (imageUrl && file && !pageImages.has(currentPage)) {
238
+ URL.revokeObjectURL(imageUrl);
239
+ }
240
+ };
241
+ }, []);
242
+ const hasImage = !!imageUrl;
243
+ const hasMultiplePages = totalPages > 1;
194
244
  useEffect(() => {
195
- if (hasFrames) {
245
+ if (hasImage) {
196
246
  setZoom(1);
197
247
  setFitMode("fit-page");
198
248
  }
199
- }, [currentIndex, hasFrames]);
249
+ }, [currentPage, hasImage]);
200
250
  useEffect(() => {
201
251
  if (typeof window === "undefined" || typeof ResizeObserver === "undefined") {
202
252
  return void 0;
@@ -235,17 +285,23 @@ var TIFFViewerContent = ({
235
285
  setZoom(1);
236
286
  }, []);
237
287
  const handleFirstPage = useCallback(() => {
238
- setCurrentIndex(0);
239
- }, []);
288
+ handlePageChange(1);
289
+ }, [handlePageChange]);
240
290
  const handleLastPage = useCallback(() => {
241
- setCurrentIndex(frames.length - 1);
242
- }, [frames.length]);
291
+ handlePageChange(totalPages);
292
+ }, [handlePageChange, totalPages]);
243
293
  const handlePreviousPage = useCallback(() => {
244
- setCurrentIndex((index) => Math.max(index - 1, 0));
245
- }, []);
294
+ const newPage = Math.max(currentPage - 1, 1);
295
+ if (newPage !== currentPage) {
296
+ handlePageChange(newPage);
297
+ }
298
+ }, [currentPage, handlePageChange]);
246
299
  const handleNextPage = useCallback(() => {
247
- setCurrentIndex((index) => Math.min(index + 1, frames.length - 1));
248
- }, [frames.length]);
300
+ const newPage = Math.min(currentPage + 1, totalPages);
301
+ if (newPage !== currentPage) {
302
+ handlePageChange(newPage);
303
+ }
304
+ }, [currentPage, totalPages, handlePageChange]);
249
305
  const handleToggleFullScreen = useCallback(() => {
250
306
  if (!isFullScreen && containerRef.current?.requestFullscreen) {
251
307
  containerRef.current.requestFullscreen();
@@ -257,53 +313,50 @@ var TIFFViewerContent = ({
257
313
  }, [isFullScreen]);
258
314
  const toolbar = mergeToolbarConfig({ showDownload, showPrint, showMetadata, showProperties, onDownloadClick, onPrintClick, onMetadataClick, onPropertiesClick, toolbarActions });
259
315
  const effectiveScale = useMemo(() => {
260
- if (!currentFrame) {
261
- return 1;
262
- }
263
316
  if (fitMode === "zoom") {
264
317
  return zoom;
265
318
  }
266
- const frameWidth = currentFrame.width;
267
- const frameHeight = currentFrame.height;
268
- if (!viewportWidth || !viewportHeight || !frameWidth || !frameHeight) {
269
- return 1;
270
- }
271
- if (fitMode === "fit-page") {
272
- const ratio = Math.min(viewportWidth / frameWidth, viewportHeight / frameHeight);
273
- return ratio || 1;
274
- }
275
- const widthRatio = viewportWidth / frameWidth;
276
- return widthRatio || 1;
277
- }, [currentFrame, fitMode, viewportWidth, viewportHeight, zoom]);
319
+ return 1;
320
+ }, [fitMode, zoom]);
278
321
  const displayScale = useMemo(() => Math.round(effectiveScale * 100), [effectiveScale]);
279
322
  const renderImage = () => {
280
- if (!currentFrame) {
281
- return /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", children: "No TIFF frame available." });
323
+ if (!imageUrl) {
324
+ return /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", children: "No image available." });
282
325
  }
283
- const widthPx = currentFrame.width * effectiveScale;
284
- const heightPx = currentFrame.height * effectiveScale;
285
326
  return /* @__PURE__ */ jsx(
286
327
  Box,
287
328
  {
288
329
  sx: {
289
330
  position: "relative",
290
- width: widthPx,
291
- height: heightPx,
292
331
  borderRadius: 1,
293
332
  boxShadow: 1,
294
- backgroundColor: "#fff"
333
+ backgroundColor: "#fff",
334
+ display: "flex",
335
+ justifyContent: "center",
336
+ alignItems: "center"
295
337
  },
296
338
  children: /* @__PURE__ */ jsx(
297
339
  Box,
298
340
  {
299
341
  component: "img",
300
- src: currentFrame.dataUrl,
301
- alt: `${resolvedFileName} page ${currentIndex + 1}`,
342
+ src: imageUrl,
343
+ alt: `${resolvedFileName} page ${currentPage}`,
302
344
  sx: {
303
- width: widthPx,
304
- height: heightPx,
345
+ maxWidth: fitMode === "fit-width" ? "100%" : "none",
346
+ maxHeight: fitMode === "fit-page" ? "100%" : "none",
347
+ width: fitMode === "zoom" ? `${zoom * 100}%` : "auto",
348
+ height: "auto",
305
349
  display: "block",
306
350
  borderRadius: 1
351
+ },
352
+ onLoad: () => {
353
+ if (!hasImage) {
354
+ onLoad?.();
355
+ }
356
+ },
357
+ onError: () => {
358
+ setError("Failed to load image");
359
+ onError?.(new Error("Failed to load image"));
307
360
  }
308
361
  }
309
362
  )
@@ -334,13 +387,13 @@ var TIFFViewerContent = ({
334
387
  }
335
388
  ),
336
389
  /* @__PURE__ */ jsx(Box, { sx: { px: 2, pb: 1, display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", flexWrap: "wrap", gap: 1, children: [
337
- hasMultipleFrames && /* @__PURE__ */ jsxs(Fragment, { children: [
390
+ hasMultiplePages && /* @__PURE__ */ jsxs(Fragment, { children: [
338
391
  /* @__PURE__ */ jsx(
339
392
  IconButton,
340
393
  {
341
394
  size: "small",
342
395
  onClick: handleFirstPage,
343
- disabled: currentIndex === 0,
396
+ disabled: currentPage === 1,
344
397
  title: "First Page",
345
398
  "aria-label": "Go to first page",
346
399
  children: /* @__PURE__ */ jsx(FirstPageIcon, { fontSize: "small" })
@@ -351,7 +404,7 @@ var TIFFViewerContent = ({
351
404
  {
352
405
  size: "small",
353
406
  onClick: handlePreviousPage,
354
- disabled: currentIndex === 0,
407
+ disabled: currentPage === 1,
355
408
  title: "Previous Page",
356
409
  "aria-label": "Go to previous page",
357
410
  children: /* @__PURE__ */ jsx(ChevronLeftIcon, { fontSize: "small" })
@@ -359,16 +412,16 @@ var TIFFViewerContent = ({
359
412
  ),
360
413
  /* @__PURE__ */ jsxs(Typography, { variant: "body2", color: "text.secondary", sx: { minWidth: 100, textAlign: "center" }, children: [
361
414
  "Page ",
362
- currentIndex + 1,
415
+ currentPage,
363
416
  " of ",
364
- frames.length
417
+ totalPages
365
418
  ] }),
366
419
  /* @__PURE__ */ jsx(
367
420
  IconButton,
368
421
  {
369
422
  size: "small",
370
423
  onClick: handleNextPage,
371
- disabled: currentIndex === frames.length - 1,
424
+ disabled: currentPage === totalPages,
372
425
  title: "Next Page",
373
426
  "aria-label": "Go to next page",
374
427
  children: /* @__PURE__ */ jsx(ChevronRightIcon, { fontSize: "small" })
@@ -379,7 +432,7 @@ var TIFFViewerContent = ({
379
432
  {
380
433
  size: "small",
381
434
  onClick: handleLastPage,
382
- disabled: currentIndex === frames.length - 1,
435
+ disabled: currentPage === totalPages,
383
436
  title: "Last Page",
384
437
  "aria-label": "Go to last page",
385
438
  children: /* @__PURE__ */ jsx(LastPageIcon, { fontSize: "small" })
@@ -392,19 +445,19 @@ var TIFFViewerContent = ({
392
445
  {
393
446
  size: "small",
394
447
  onClick: handleZoomOut,
395
- disabled: !hasFrames || zoom <= 0.25,
448
+ disabled: !hasImage || zoom <= 0.25,
396
449
  title: "Zoom Out",
397
450
  "aria-label": "Zoom out",
398
451
  children: /* @__PURE__ */ jsx(ZoomOutIcon, { fontSize: "small" })
399
452
  }
400
453
  ),
401
- /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", sx: { minWidth: 64, textAlign: "center" }, children: hasFrames ? `${displayScale}%` : "\u2014" }),
454
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", sx: { minWidth: 64, textAlign: "center" }, children: hasImage ? `${displayScale}%` : "\u2014" }),
402
455
  /* @__PURE__ */ jsx(
403
456
  IconButton,
404
457
  {
405
458
  size: "small",
406
459
  onClick: handleZoomIn,
407
- disabled: !hasFrames || zoom >= 5,
460
+ disabled: !hasImage || zoom >= 5,
408
461
  title: "Zoom In",
409
462
  "aria-label": "Zoom in",
410
463
  children: /* @__PURE__ */ jsx(ZoomInIcon, { fontSize: "small" })
@@ -415,7 +468,7 @@ var TIFFViewerContent = ({
415
468
  {
416
469
  size: "small",
417
470
  onClick: handleFitWidth,
418
- disabled: !hasFrames,
471
+ disabled: !hasImage,
419
472
  title: "Fit to Width",
420
473
  "aria-label": "Fit to width",
421
474
  color: fitMode === "fit-width" ? "primary" : "default",
@@ -427,7 +480,7 @@ var TIFFViewerContent = ({
427
480
  {
428
481
  size: "small",
429
482
  onClick: handleFitPage,
430
- disabled: !hasFrames,
483
+ disabled: !hasImage,
431
484
  title: "Fit to Page",
432
485
  "aria-label": "Fit to page",
433
486
  color: fitMode === "fit-page" ? "primary" : "default",
@@ -491,7 +544,7 @@ var TIFFViewerContent = ({
491
544
  }
492
545
  )
493
546
  ] }) }),
494
- isLoading && /* @__PURE__ */ jsx(LinearProgress, { sx: { mx: 3, mb: 1 } }),
547
+ (isLoading || internalLoading) && /* @__PURE__ */ jsx(LinearProgress, { sx: { mx: 3, mb: 1 } }),
495
548
  error && /* @__PURE__ */ jsx(Typography, { color: "error", variant: "body2", sx: { px: 3, pb: 1 }, children: error }),
496
549
  /* @__PURE__ */ jsx(Divider, {}),
497
550
  /* @__PURE__ */ jsx(
@@ -542,4 +595,4 @@ var TIFFViewer = (props) => {
542
595
  export {
543
596
  TIFFViewer
544
597
  };
545
- //# sourceMappingURL=chunk-PFJKVNUA.mjs.map
598
+ //# sourceMappingURL=chunk-ZUA4KYTB.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/viewers/TIFFViewer.tsx"],"sourcesContent":["import React, {\r\n useCallback,\r\n useEffect,\r\n useMemo,\r\n useRef,\r\n useState\r\n} from 'react';\r\nimport {\r\n Box,\r\n Button,\r\n ButtonGroup,\r\n Card,\r\n CardContent,\r\n CardHeader,\r\n Divider,\r\n LinearProgress,\r\n Stack,\r\n Typography,\r\n IconButton,\r\n Tooltip\r\n} from '@mui/material';\r\nimport DownloadIcon from '@mui/icons-material/Download';\r\nimport PrintIcon from '@mui/icons-material/Print';\r\nimport FullscreenIcon from '@mui/icons-material/Fullscreen';\r\nimport FirstPageIcon from '@mui/icons-material/FirstPage';\r\nimport LastPageIcon from '@mui/icons-material/LastPage';\r\nimport ChevronLeftIcon from '@mui/icons-material/ChevronLeft';\r\nimport ChevronRightIcon from '@mui/icons-material/ChevronRight';\r\nimport ZoomInIcon from '@mui/icons-material/ZoomIn';\r\nimport ZoomOutIcon from '@mui/icons-material/ZoomOut';\r\nimport FitScreenIcon from '@mui/icons-material/FitScreen';\r\nimport AspectRatioIcon from '@mui/icons-material/AspectRatio';\r\nimport InfoIcon from '@mui/icons-material/Info';\r\nimport DescriptionIcon from '@mui/icons-material/Description';\r\nimport { FileViewerProps } from '../../types';\r\nimport { getFileExtension } from '../../utils/fileUtils';\r\nimport { mergeToolbarConfig } from '../../utils/toolbarUtils';\r\nimport FileIcon from '../FileIcon';\r\n\r\nconst resolveDocumentName = (file?: File, fileName?: string, url?: string) => {\r\n if (file?.name) {\r\n return file.name;\r\n }\r\n if (fileName) {\r\n return fileName;\r\n }\r\n if (url) {\r\n const parts = url.split('?')[0]?.split('#')[0]?.split('/') ?? [];\r\n return parts[parts.length - 1] || 'document.tiff';\r\n }\r\n return 'document.tiff';\r\n};\r\n\r\ninterface TIFFViewerContentProps extends FileViewerProps {\r\n sourceDescription: string;\r\n}\r\n\r\nconst TIFFViewerContent: React.FC<TIFFViewerContentProps> = ({\r\n sourceDescription,\r\n file,\r\n url,\r\n fileName,\r\n totalPages = 1,\r\n className = '',\r\n style = {},\r\n width = '100%',\r\n height = '100%',\r\n onLoad,\r\n onError,\r\n onDownloadClick,\r\n onPrintClick,\r\n onMetadataClick,\r\n onPropertiesClick,\r\n pageLoader,\r\n showDownload = true,\r\n showPrint = true,\r\n showMetadata = false,\r\n showProperties = false,\r\n // Extract props that shouldn't be passed to DOM elements\r\n mimeType,\r\n fileSize,\r\n showPageCount,\r\n showPageNavigation,\r\n showZoomControls,\r\n showSearch,\r\n customRegistry,\r\n initialSearchText,\r\n initialSearchPages,\r\n autoOpenSearch,\r\n autoExecuteSearch,\r\n onSearchComplete,\r\n toolbarActions,\r\n ...props\r\n}) => {\r\n const [currentPage, setCurrentPage] = useState(1);\r\n const [isLoading, setIsLoading] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const [fitMode, setFitMode] = useState<'fit-width' | 'fit-page' | 'zoom'>('fit-page');\r\n const [zoom, setZoom] = useState(1);\r\n const [viewportWidth, setViewportWidth] = useState<number>(0);\r\n const [viewportHeight, setViewportHeight] = useState<number>(0);\r\n const [isFullScreen, setIsFullScreen] = useState(false);\r\n const [imageUrl, setImageUrl] = useState<string | null>(null);\r\n const [pageImages, setPageImages] = useState<Map<number, string>>(new Map());\r\n const [internalLoading, setInternalLoading] = useState(false);\r\n \r\n const viewportRef = useRef<HTMLDivElement | null>(null);\r\n const containerRef = useRef<HTMLDivElement>(null);\r\n \r\n // Store pageLoader in ref to prevent re-renders\r\n const pageLoaderRef = useRef(pageLoader);\r\n useEffect(() => {\r\n pageLoaderRef.current = pageLoader;\r\n }, [pageLoader]);\r\n\r\n // Update page image from ArrayBuffer data\r\n const updatePageImage = useCallback((pageData: ArrayBuffer, pageNumber: number) => {\r\n const blob = new Blob([pageData]);\r\n const imageUrl = URL.createObjectURL(blob);\r\n \r\n setPageImages(prev => {\r\n // Only clean up old URL if we're replacing with a different one\r\n const oldUrl = prev.get(pageNumber);\r\n if (oldUrl && oldUrl !== imageUrl) {\r\n URL.revokeObjectURL(oldUrl);\r\n }\r\n return new Map(prev).set(pageNumber, imageUrl);\r\n });\r\n setCurrentPage(pageNumber);\r\n setImageUrl(imageUrl);\r\n }, []);\r\n\r\n // Load initial page when pageLoader is available\r\n useEffect(() => {\r\n const loadInitialPage = async () => {\r\n if (pageLoaderRef.current && !pageImages.has(1) && currentPage === 1) {\r\n setInternalLoading(true);\r\n setError(null);\r\n \r\n try {\r\n const pageData = await pageLoaderRef.current(1);\r\n if (pageData) {\r\n updatePageImage(pageData, 1);\r\n } else {\r\n setError('Failed to load page 1');\r\n }\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : 'Unable to load page 1';\r\n setError(message);\r\n onError?.(new Error(message));\r\n } finally {\r\n setInternalLoading(false);\r\n }\r\n }\r\n };\r\n\r\n loadInitialPage();\r\n }, [pageImages, currentPage, updatePageImage, onError]);\r\n\r\n // Handle internal page navigation\r\n const handlePageChange = useCallback(async (newPageNumber: number) => {\r\n if (!pageLoaderRef.current) {\r\n console.warn('pageLoader not provided - page navigation disabled');\r\n return;\r\n }\r\n\r\n // Check if page is already cached\r\n const cachedUrl = pageImages.get(newPageNumber);\r\n if (cachedUrl) {\r\n setCurrentPage(newPageNumber);\r\n setImageUrl(cachedUrl);\r\n return;\r\n }\r\n\r\n setInternalLoading(true);\r\n setError(null);\r\n \r\n try {\r\n const pageData = await pageLoaderRef.current(newPageNumber);\r\n if (pageData) {\r\n updatePageImage(pageData, newPageNumber);\r\n } else {\r\n setError(`Failed to load page ${newPageNumber}`);\r\n }\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : `Unable to load page ${newPageNumber}`;\r\n setError(message);\r\n onError?.(new Error(message));\r\n } finally {\r\n setInternalLoading(false);\r\n }\r\n }, [pageImages, onError, updatePageImage]);\r\n\r\n const resolvedFileName = useMemo(\r\n () => fileName || sourceDescription,\r\n [fileName, sourceDescription]\r\n );\r\n\r\n const fileExtension = useMemo(\r\n () => getFileExtension(resolvedFileName || ''),\r\n [resolvedFileName]\r\n );\r\n\r\n const loadImage = useCallback(async (resetPage = false) => {\r\n if (!file && !url) {\r\n setImageUrl(null);\r\n if (resetPage) setCurrentPage(1);\r\n setError(null);\r\n return;\r\n }\r\n\r\n setIsLoading(true);\r\n setError(null);\r\n\r\n try {\r\n let imageDataUrl: string;\r\n if (file) {\r\n imageDataUrl = URL.createObjectURL(file);\r\n } else if (url) {\r\n imageDataUrl = url;\r\n } else {\r\n throw new Error('No file or URL provided');\r\n }\r\n\r\n setImageUrl(imageDataUrl);\r\n if (resetPage) {\r\n setCurrentPage(1);\r\n setFitMode('fit-page');\r\n setZoom(1);\r\n }\r\n onLoad?.();\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : 'Unable to load image file';\r\n setError(message);\r\n setImageUrl(null);\r\n if (resetPage) {\r\n setCurrentPage(1);\r\n setFitMode('fit-page');\r\n setZoom(1);\r\n }\r\n onError?.(new Error(message));\r\n } finally {\r\n setIsLoading(false);\r\n }\r\n }, [file, url, onLoad, onError]);\r\n\r\n const [previousFileSource, setPreviousFileSource] = useState<{ file?: File; url?: string }>({});\r\n\r\n useEffect(() => {\r\n const currentFileSource = { file, url };\r\n const isNewFile = previousFileSource.file !== file || previousFileSource.url !== url;\r\n \r\n if (isNewFile) {\r\n setPreviousFileSource(currentFileSource);\r\n void loadImage(true); // Reset page on new file\r\n } else {\r\n void loadImage(false); // Don't reset page for same file\r\n }\r\n }, [file, url, loadImage, previousFileSource.file, previousFileSource.url]);\r\n\r\n useEffect(() => {\r\n return () => {\r\n // Clean up all cached page URLs only on unmount\r\n pageImages.forEach((url) => {\r\n URL.revokeObjectURL(url);\r\n });\r\n // Clean up current image URL if it's from a file (not from pageLoader)\r\n if (imageUrl && file && !pageImages.has(currentPage)) {\r\n URL.revokeObjectURL(imageUrl);\r\n }\r\n };\r\n }, []); // Empty dependency array - only cleanup on unmount\r\n\r\n const hasImage = !!imageUrl;\r\n const hasMultiplePages = totalPages > 1;\r\n\r\n useEffect(() => {\r\n if (hasImage) {\r\n setZoom(1);\r\n setFitMode('fit-page');\r\n }\r\n }, [currentPage, hasImage]);\r\n\r\n useEffect(() => {\r\n if (typeof window === 'undefined' || typeof ResizeObserver === 'undefined') {\r\n return undefined;\r\n }\r\n\r\n if (!viewportRef.current) {\r\n return undefined;\r\n }\r\n\r\n const updateSize = () => {\r\n const bounds = viewportRef.current?.getBoundingClientRect();\r\n if (bounds) {\r\n setViewportWidth(bounds.width);\r\n setViewportHeight(bounds.height);\r\n }\r\n };\r\n\r\n updateSize();\r\n const observer = new ResizeObserver(updateSize);\r\n observer.observe(viewportRef.current);\r\n\r\n return () => {\r\n observer.disconnect();\r\n };\r\n }, []);\r\n\r\n const handleZoomIn = useCallback(() => {\r\n setFitMode('zoom');\r\n setZoom((value) => Math.min(Math.round((value + 0.25) * 100) / 100, 5));\r\n }, []);\r\n\r\n const handleZoomOut = useCallback(() => {\r\n setFitMode('zoom');\r\n setZoom((value) => Math.max(Math.round((value - 0.25) * 100) / 100, 0.25));\r\n }, []);\r\n\r\n const handleFitWidth = useCallback(() => {\r\n setFitMode('fit-width');\r\n setZoom(1);\r\n }, []);\r\n\r\n const handleFitPage = useCallback(() => {\r\n setFitMode('fit-page');\r\n setZoom(1);\r\n }, []);\r\n\r\n const handleFirstPage = useCallback(() => {\r\n handlePageChange(1);\r\n }, [handlePageChange]);\r\n\r\n const handleLastPage = useCallback(() => {\r\n handlePageChange(totalPages);\r\n }, [handlePageChange, totalPages]);\r\n\r\n const handlePreviousPage = useCallback(() => {\r\n const newPage = Math.max(currentPage - 1, 1);\r\n if (newPage !== currentPage) {\r\n handlePageChange(newPage);\r\n }\r\n }, [currentPage, handlePageChange]);\r\n\r\n const handleNextPage = useCallback(() => {\r\n const newPage = Math.min(currentPage + 1, totalPages);\r\n if (newPage !== currentPage) {\r\n handlePageChange(newPage);\r\n }\r\n }, [currentPage, totalPages, handlePageChange]);\r\n\r\n const handleToggleFullScreen = useCallback(() => {\r\n if (!isFullScreen && containerRef.current?.requestFullscreen) {\r\n containerRef.current.requestFullscreen();\r\n setIsFullScreen(true);\r\n } else if (isFullScreen && document.exitFullscreen) {\r\n document.exitFullscreen();\r\n setIsFullScreen(false);\r\n }\r\n }, [isFullScreen]);\r\n\r\n const toolbar = mergeToolbarConfig({ showDownload, showPrint, showMetadata, showProperties, onDownloadClick, onPrintClick, onMetadataClick, onPropertiesClick, toolbarActions });\r\n\r\n const effectiveScale = useMemo(() => {\r\n if (fitMode === 'zoom') {\r\n return zoom;\r\n }\r\n return 1;\r\n }, [fitMode, zoom]);\r\n\r\n const displayScale = useMemo(() => Math.round(effectiveScale * 100), [effectiveScale]);\r\n\r\n const renderImage = () => {\r\n if (!imageUrl) {\r\n return (\r\n <Typography variant=\"body2\" color=\"text.secondary\">\r\n No image available.\r\n </Typography>\r\n );\r\n }\r\n\r\n return (\r\n <Box\r\n sx={{\r\n position: 'relative',\r\n borderRadius: 1,\r\n boxShadow: 1,\r\n backgroundColor: '#fff',\r\n display: 'flex',\r\n justifyContent: 'center',\r\n alignItems: 'center'\r\n }}\r\n >\r\n <Box\r\n component=\"img\"\r\n src={imageUrl}\r\n alt={`${resolvedFileName} page ${currentPage}`}\r\n sx={{\r\n maxWidth: fitMode === 'fit-width' ? '100%' : 'none',\r\n maxHeight: fitMode === 'fit-page' ? '100%' : 'none',\r\n width: fitMode === 'zoom' ? `${zoom * 100}%` : 'auto',\r\n height: 'auto',\r\n display: 'block',\r\n borderRadius: 1\r\n }}\r\n onLoad={() => {\r\n if (!hasImage) {\r\n onLoad?.();\r\n }\r\n }}\r\n onError={() => {\r\n setError('Failed to load image');\r\n onError?.(new Error('Failed to load image'));\r\n }}\r\n />\r\n </Box>\r\n );\r\n };\r\n\r\n return (\r\n <Box\r\n ref={containerRef}\r\n className={`tiff-viewer ${className}`}\r\n sx={{\r\n width,\r\n height,\r\n display: 'flex',\r\n flexDirection: 'column',\r\n overflow: 'hidden',\r\n ...style\r\n }}\r\n {...props}\r\n >\r\n <Card sx={{ height: '100%', width: '100%', display: 'flex', flexDirection: 'column', overflow: 'hidden' }} elevation={1}>\r\n <CardHeader\r\n avatar={<FileIcon ext={fileExtension} size={32} />}\r\n title={\r\n <Typography variant=\"subtitle1\" fontWeight={500}>\r\n {resolvedFileName}\r\n </Typography>\r\n }\r\n sx={{ pb: 1 }}\r\n />\r\n\r\n {/* Toolbar - All Controls at Top (Centered) */}\r\n <Box sx={{ px: 2, pb: 1, display: 'flex', justifyContent: 'center' }}>\r\n <Stack direction=\"row\" spacing={1} alignItems=\"center\" flexWrap=\"wrap\" gap={1}>\r\n {/* Page Navigation */}\r\n {hasMultiplePages && (\r\n <>\r\n <IconButton\r\n size=\"small\"\r\n onClick={handleFirstPage}\r\n disabled={currentPage === 1}\r\n title=\"First Page\"\r\n aria-label=\"Go to first page\"\r\n >\r\n <FirstPageIcon fontSize=\"small\" />\r\n </IconButton>\r\n <IconButton\r\n size=\"small\"\r\n onClick={handlePreviousPage}\r\n disabled={currentPage === 1}\r\n title=\"Previous Page\"\r\n aria-label=\"Go to previous page\"\r\n >\r\n <ChevronLeftIcon fontSize=\"small\" />\r\n </IconButton>\r\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ minWidth: 100, textAlign: 'center' }}>\r\n Page {currentPage} of {totalPages}\r\n </Typography>\r\n <IconButton\r\n size=\"small\"\r\n onClick={handleNextPage}\r\n disabled={currentPage === totalPages}\r\n title=\"Next Page\"\r\n aria-label=\"Go to next page\"\r\n >\r\n <ChevronRightIcon fontSize=\"small\" />\r\n </IconButton>\r\n <IconButton\r\n size=\"small\"\r\n onClick={handleLastPage}\r\n disabled={currentPage === totalPages}\r\n title=\"Last Page\"\r\n aria-label=\"Go to last page\"\r\n >\r\n <LastPageIcon fontSize=\"small\" />\r\n </IconButton>\r\n <Divider orientation=\"vertical\" flexItem sx={{ mx: 1 }} />\r\n </>\r\n )}\r\n\r\n {/* Zoom Controls */}\r\n <IconButton\r\n size=\"small\"\r\n onClick={handleZoomOut}\r\n disabled={!hasImage || zoom <= 0.25}\r\n title=\"Zoom Out\"\r\n aria-label=\"Zoom out\"\r\n >\r\n <ZoomOutIcon fontSize=\"small\" />\r\n </IconButton>\r\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ minWidth: 64, textAlign: 'center' }}>\r\n {hasImage ? `${displayScale}%` : '—'}\r\n </Typography>\r\n <IconButton\r\n size=\"small\"\r\n onClick={handleZoomIn}\r\n disabled={!hasImage || zoom >= 5}\r\n title=\"Zoom In\"\r\n aria-label=\"Zoom in\"\r\n >\r\n <ZoomInIcon fontSize=\"small\" />\r\n </IconButton>\r\n\r\n <IconButton\r\n size=\"small\"\r\n onClick={handleFitWidth}\r\n disabled={!hasImage}\r\n title=\"Fit to Width\"\r\n aria-label=\"Fit to width\"\r\n color={fitMode === 'fit-width' ? 'primary' : 'default'}\r\n >\r\n <AspectRatioIcon fontSize=\"small\" />\r\n </IconButton>\r\n\r\n <IconButton\r\n size=\"small\"\r\n onClick={handleFitPage}\r\n disabled={!hasImage}\r\n title=\"Fit to Page\"\r\n aria-label=\"Fit to page\"\r\n color={fitMode === 'fit-page' ? 'primary' : 'default'}\r\n >\r\n <FitScreenIcon fontSize=\"small\" />\r\n </IconButton>\r\n\r\n <Divider orientation=\"vertical\" flexItem sx={{ mx: 1 }} />\r\n\r\n {/* Actions */}\r\n {!toolbar.isHidden('download') && (\r\n <IconButton\r\n size=\"small\"\r\n onClick={toolbar.getHandler('download', onDownloadClick)}\r\n disabled={toolbar.isDisabled('download')}\r\n title={toolbar.getLabel('download') || \"Download\"}\r\n aria-label=\"Download TIFF\"\r\n >\r\n {toolbar.getIcon('download') || <DownloadIcon fontSize=\"small\" />}\r\n </IconButton>\r\n )}\r\n\r\n {!toolbar.isHidden('print') && (\r\n <IconButton\r\n size=\"small\"\r\n onClick={toolbar.getHandler('print', onPrintClick)}\r\n disabled={toolbar.isDisabled('print')}\r\n title={toolbar.getLabel('print') || \"Print\"}\r\n aria-label=\"Print TIFF\"\r\n >\r\n {toolbar.getIcon('print') || <PrintIcon fontSize=\"small\" />}\r\n </IconButton>\r\n )}\r\n\r\n {!toolbar.isHidden('fullscreen') && (\r\n <IconButton\r\n size=\"small\"\r\n onClick={toolbar.getHandler('fullscreen', handleToggleFullScreen)}\r\n disabled={toolbar.isDisabled('fullscreen')}\r\n title={toolbar.getLabel('fullscreen') || \"Fullscreen\"}\r\n aria-label=\"Toggle fullscreen\"\r\n >\r\n {toolbar.getIcon('fullscreen') || <FullscreenIcon fontSize=\"small\" />}\r\n </IconButton>\r\n )}\r\n\r\n {!toolbar.isHidden('metadata') && (\r\n <IconButton\r\n size=\"small\"\r\n onClick={toolbar.getHandler('metadata', onMetadataClick)}\r\n disabled={toolbar.isDisabled('metadata')}\r\n title={toolbar.getLabel('metadata') || \"Document Metadata\"}\r\n aria-label=\"View document metadata\"\r\n >\r\n {toolbar.getIcon('metadata') || <DescriptionIcon fontSize=\"small\" />}\r\n </IconButton>\r\n )}\r\n\r\n {!toolbar.isHidden('properties') && (\r\n <IconButton\r\n size=\"small\"\r\n onClick={toolbar.getHandler('properties', onPropertiesClick)}\r\n disabled={toolbar.isDisabled('properties')}\r\n title={toolbar.getLabel('properties') || \"Document Properties\"}\r\n aria-label=\"View document properties\"\r\n >\r\n {toolbar.getIcon('properties') || <InfoIcon fontSize=\"small\" />}\r\n </IconButton>\r\n )}\r\n </Stack>\r\n </Box>\r\n\r\n {(isLoading || internalLoading) && <LinearProgress sx={{ mx: 3, mb: 1 }} />}\r\n {error && (\r\n <Typography color=\"error\" variant=\"body2\" sx={{ px: 3, pb: 1 }}>\r\n {error}\r\n </Typography>\r\n )}\r\n <Divider />\r\n <CardContent\r\n sx={{\r\n flexGrow: 1,\r\n flexShrink: 1,\r\n minHeight: 0,\r\n p: 0,\r\n overflow: 'auto',\r\n backgroundColor: '#f6f8fa',\r\n position: 'relative'\r\n }}\r\n >\r\n <Box\r\n ref={viewportRef}\r\n sx={{\r\n position: 'absolute',\r\n top: 0,\r\n left: 0,\r\n right: 0,\r\n bottom: 0,\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n p: 3,\r\n overflow: 'auto'\r\n }}\r\n >\r\n {renderImage()}\r\n </Box>\r\n </CardContent>\r\n </Card>\r\n </Box>\r\n );\r\n};\r\n\r\nexport const TIFFViewer: React.FC<FileViewerProps> = (props) => {\r\n const sourceDescription = useMemo(\r\n () => resolveDocumentName(props.file, props.fileName, props.url),\r\n [props.file, props.fileName, props.url]\r\n );\r\n\r\n return <TIFFViewerContent {...props} sourceDescription={sourceDescription} />;\r\n};\r\n"],"mappings":";;;;;;;;;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,OAAO,kBAAkB;AACzB,OAAO,eAAe;AACtB,OAAO,oBAAoB;AAC3B,OAAO,mBAAmB;AAC1B,OAAO,kBAAkB;AACzB,OAAO,qBAAqB;AAC5B,OAAO,sBAAsB;AAC7B,OAAO,gBAAgB;AACvB,OAAO,iBAAiB;AACxB,OAAO,mBAAmB;AAC1B,OAAO,qBAAqB;AAC5B,OAAO,cAAc;AACrB,OAAO,qBAAqB;AAsVpB,SA0EM,UA1EN,KA6FQ,YA7FR;AAhVR,IAAM,sBAAsB,CAAC,MAAa,UAAmB,QAAiB;AAC5E,MAAI,MAAM,MAAM;AACd,WAAO,KAAK;AAAA,EACd;AACA,MAAI,UAAU;AACZ,WAAO;AAAA,EACT;AACA,MAAI,KAAK;AACP,UAAM,QAAQ,IAAI,MAAM,GAAG,EAAE,CAAC,GAAG,MAAM,GAAG,EAAE,CAAC,GAAG,MAAM,GAAG,KAAK,CAAC;AAC/D,WAAO,MAAM,MAAM,SAAS,CAAC,KAAK;AAAA,EACpC;AACA,SAAO;AACT;AAMA,IAAM,oBAAsD,CAAC;AAAA,EAC3D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,QAAQ,CAAC;AAAA,EACT,QAAQ;AAAA,EACR,SAAS;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,iBAAiB;AAAA;AAAA,EAEjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAAM;AACJ,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,CAAC;AAChD,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAChD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AACtD,QAAM,CAAC,SAAS,UAAU,IAAI,SAA4C,UAAU;AACpF,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,CAAC;AAClC,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAiB,CAAC;AAC5D,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAiB,CAAC;AAC9D,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,KAAK;AACtD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAwB,IAAI;AAC5D,QAAM,CAAC,YAAY,aAAa,IAAI,SAA8B,oBAAI,IAAI,CAAC;AAC3E,QAAM,CAAC,iBAAiB,kBAAkB,IAAI,SAAS,KAAK;AAE5D,QAAM,cAAc,OAA8B,IAAI;AACtD,QAAM,eAAe,OAAuB,IAAI;AAGhD,QAAM,gBAAgB,OAAO,UAAU;AACvC,YAAU,MAAM;AACd,kBAAc,UAAU;AAAA,EAC1B,GAAG,CAAC,UAAU,CAAC;AAGf,QAAM,kBAAkB,YAAY,CAAC,UAAuB,eAAuB;AACjF,UAAM,OAAO,IAAI,KAAK,CAAC,QAAQ,CAAC;AAChC,UAAMA,YAAW,IAAI,gBAAgB,IAAI;AAEzC,kBAAc,UAAQ;AAEpB,YAAM,SAAS,KAAK,IAAI,UAAU;AAClC,UAAI,UAAU,WAAWA,WAAU;AACjC,YAAI,gBAAgB,MAAM;AAAA,MAC5B;AACA,aAAO,IAAI,IAAI,IAAI,EAAE,IAAI,YAAYA,SAAQ;AAAA,IAC/C,CAAC;AACD,mBAAe,UAAU;AACzB,gBAAYA,SAAQ;AAAA,EACtB,GAAG,CAAC,CAAC;AAGL,YAAU,MAAM;AACd,UAAM,kBAAkB,YAAY;AAClC,UAAI,cAAc,WAAW,CAAC,WAAW,IAAI,CAAC,KAAK,gBAAgB,GAAG;AACpE,2BAAmB,IAAI;AACvB,iBAAS,IAAI;AAEb,YAAI;AACF,gBAAM,WAAW,MAAM,cAAc,QAAQ,CAAC;AAC9C,cAAI,UAAU;AACZ,4BAAgB,UAAU,CAAC;AAAA,UAC7B,OAAO;AACL,qBAAS,uBAAuB;AAAA,UAClC;AAAA,QACF,SAAS,KAAK;AACZ,gBAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,mBAAS,OAAO;AAChB,oBAAU,IAAI,MAAM,OAAO,CAAC;AAAA,QAC9B,UAAE;AACA,6BAAmB,KAAK;AAAA,QAC1B;AAAA,MACF;AAAA,IACF;AAEA,oBAAgB;AAAA,EAClB,GAAG,CAAC,YAAY,aAAa,iBAAiB,OAAO,CAAC;AAGtD,QAAM,mBAAmB,YAAY,OAAO,kBAA0B;AACpE,QAAI,CAAC,cAAc,SAAS;AAC1B,cAAQ,KAAK,oDAAoD;AACjE;AAAA,IACF;AAGA,UAAM,YAAY,WAAW,IAAI,aAAa;AAC9C,QAAI,WAAW;AACb,qBAAe,aAAa;AAC5B,kBAAY,SAAS;AACrB;AAAA,IACF;AAEA,uBAAmB,IAAI;AACvB,aAAS,IAAI;AAEb,QAAI;AACF,YAAM,WAAW,MAAM,cAAc,QAAQ,aAAa;AAC1D,UAAI,UAAU;AACZ,wBAAgB,UAAU,aAAa;AAAA,MACzC,OAAO;AACL,iBAAS,uBAAuB,aAAa,EAAE;AAAA,MACjD;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,uBAAuB,aAAa;AACzF,eAAS,OAAO;AAChB,gBAAU,IAAI,MAAM,OAAO,CAAC;AAAA,IAC9B,UAAE;AACA,yBAAmB,KAAK;AAAA,IAC1B;AAAA,EACF,GAAG,CAAC,YAAY,SAAS,eAAe,CAAC;AAEzC,QAAM,mBAAmB;AAAA,IACvB,MAAM,YAAY;AAAA,IAClB,CAAC,UAAU,iBAAiB;AAAA,EAC9B;AAEA,QAAM,gBAAgB;AAAA,IACpB,MAAM,iBAAiB,oBAAoB,EAAE;AAAA,IAC7C,CAAC,gBAAgB;AAAA,EACnB;AAEA,QAAM,YAAY,YAAY,OAAO,YAAY,UAAU;AACzD,QAAI,CAAC,QAAQ,CAAC,KAAK;AACjB,kBAAY,IAAI;AAChB,UAAI,UAAW,gBAAe,CAAC;AAC/B,eAAS,IAAI;AACb;AAAA,IACF;AAEA,iBAAa,IAAI;AACjB,aAAS,IAAI;AAEb,QAAI;AACF,UAAI;AACJ,UAAI,MAAM;AACR,uBAAe,IAAI,gBAAgB,IAAI;AAAA,MACzC,WAAW,KAAK;AACd,uBAAe;AAAA,MACjB,OAAO;AACL,cAAM,IAAI,MAAM,yBAAyB;AAAA,MAC3C;AAEA,kBAAY,YAAY;AACxB,UAAI,WAAW;AACb,uBAAe,CAAC;AAChB,mBAAW,UAAU;AACrB,gBAAQ,CAAC;AAAA,MACX;AACA,eAAS;AAAA,IACX,SAAS,KAAK;AACZ,YAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,eAAS,OAAO;AAChB,kBAAY,IAAI;AAChB,UAAI,WAAW;AACb,uBAAe,CAAC;AAChB,mBAAW,UAAU;AACrB,gBAAQ,CAAC;AAAA,MACX;AACA,gBAAU,IAAI,MAAM,OAAO,CAAC;AAAA,IAC9B,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,MAAM,KAAK,QAAQ,OAAO,CAAC;AAE/B,QAAM,CAAC,oBAAoB,qBAAqB,IAAI,SAAwC,CAAC,CAAC;AAE9F,YAAU,MAAM;AACd,UAAM,oBAAoB,EAAE,MAAM,IAAI;AACtC,UAAM,YAAY,mBAAmB,SAAS,QAAQ,mBAAmB,QAAQ;AAEjF,QAAI,WAAW;AACb,4BAAsB,iBAAiB;AACvC,WAAK,UAAU,IAAI;AAAA,IACrB,OAAO;AACL,WAAK,UAAU,KAAK;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,MAAM,KAAK,WAAW,mBAAmB,MAAM,mBAAmB,GAAG,CAAC;AAE1E,YAAU,MAAM;AACd,WAAO,MAAM;AAEX,iBAAW,QAAQ,CAACC,SAAQ;AAC1B,YAAI,gBAAgBA,IAAG;AAAA,MACzB,CAAC;AAED,UAAI,YAAY,QAAQ,CAAC,WAAW,IAAI,WAAW,GAAG;AACpD,YAAI,gBAAgB,QAAQ;AAAA,MAC9B;AAAA,IACF;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,WAAW,CAAC,CAAC;AACnB,QAAM,mBAAmB,aAAa;AAEtC,YAAU,MAAM;AACd,QAAI,UAAU;AACZ,cAAQ,CAAC;AACT,iBAAW,UAAU;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,aAAa,QAAQ,CAAC;AAE1B,YAAU,MAAM;AACd,QAAI,OAAO,WAAW,eAAe,OAAO,mBAAmB,aAAa;AAC1E,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,YAAY,SAAS;AACxB,aAAO;AAAA,IACT;AAEA,UAAM,aAAa,MAAM;AACvB,YAAM,SAAS,YAAY,SAAS,sBAAsB;AAC1D,UAAI,QAAQ;AACV,yBAAiB,OAAO,KAAK;AAC7B,0BAAkB,OAAO,MAAM;AAAA,MACjC;AAAA,IACF;AAEA,eAAW;AACX,UAAM,WAAW,IAAI,eAAe,UAAU;AAC9C,aAAS,QAAQ,YAAY,OAAO;AAEpC,WAAO,MAAM;AACX,eAAS,WAAW;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,eAAe,YAAY,MAAM;AACrC,eAAW,MAAM;AACjB,YAAQ,CAAC,UAAU,KAAK,IAAI,KAAK,OAAO,QAAQ,QAAQ,GAAG,IAAI,KAAK,CAAC,CAAC;AAAA,EACxE,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAgB,YAAY,MAAM;AACtC,eAAW,MAAM;AACjB,YAAQ,CAAC,UAAU,KAAK,IAAI,KAAK,OAAO,QAAQ,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC;AAAA,EAC3E,GAAG,CAAC,CAAC;AAEL,QAAM,iBAAiB,YAAY,MAAM;AACvC,eAAW,WAAW;AACtB,YAAQ,CAAC;AAAA,EACX,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAgB,YAAY,MAAM;AACtC,eAAW,UAAU;AACrB,YAAQ,CAAC;AAAA,EACX,GAAG,CAAC,CAAC;AAEL,QAAM,kBAAkB,YAAY,MAAM;AACxC,qBAAiB,CAAC;AAAA,EACpB,GAAG,CAAC,gBAAgB,CAAC;AAErB,QAAM,iBAAiB,YAAY,MAAM;AACvC,qBAAiB,UAAU;AAAA,EAC7B,GAAG,CAAC,kBAAkB,UAAU,CAAC;AAEjC,QAAM,qBAAqB,YAAY,MAAM;AAC3C,UAAM,UAAU,KAAK,IAAI,cAAc,GAAG,CAAC;AAC3C,QAAI,YAAY,aAAa;AAC3B,uBAAiB,OAAO;AAAA,IAC1B;AAAA,EACF,GAAG,CAAC,aAAa,gBAAgB,CAAC;AAElC,QAAM,iBAAiB,YAAY,MAAM;AACvC,UAAM,UAAU,KAAK,IAAI,cAAc,GAAG,UAAU;AACpD,QAAI,YAAY,aAAa;AAC3B,uBAAiB,OAAO;AAAA,IAC1B;AAAA,EACF,GAAG,CAAC,aAAa,YAAY,gBAAgB,CAAC;AAE9C,QAAM,yBAAyB,YAAY,MAAM;AAC/C,QAAI,CAAC,gBAAgB,aAAa,SAAS,mBAAmB;AAC5D,mBAAa,QAAQ,kBAAkB;AACvC,sBAAgB,IAAI;AAAA,IACtB,WAAW,gBAAgB,SAAS,gBAAgB;AAClD,eAAS,eAAe;AACxB,sBAAgB,KAAK;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,YAAY,CAAC;AAEjB,QAAM,UAAU,mBAAmB,EAAE,cAAc,WAAW,cAAc,gBAAgB,iBAAiB,cAAc,iBAAiB,mBAAmB,eAAe,CAAC;AAE/K,QAAM,iBAAiB,QAAQ,MAAM;AACnC,QAAI,YAAY,QAAQ;AACtB,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,GAAG,CAAC,SAAS,IAAI,CAAC;AAElB,QAAM,eAAe,QAAQ,MAAM,KAAK,MAAM,iBAAiB,GAAG,GAAG,CAAC,cAAc,CAAC;AAErF,QAAM,cAAc,MAAM;AACxB,QAAI,CAAC,UAAU;AACb,aACE,oBAAC,cAAW,SAAQ,SAAQ,OAAM,kBAAiB,iCAEnD;AAAA,IAEJ;AAEA,WACE;AAAA,MAAC;AAAA;AAAA,QACC,IAAI;AAAA,UACF,UAAU;AAAA,UACV,cAAc;AAAA,UACd,WAAW;AAAA,UACX,iBAAiB;AAAA,UACjB,SAAS;AAAA,UACT,gBAAgB;AAAA,UAChB,YAAY;AAAA,QACd;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,KAAK;AAAA,YACL,KAAK,GAAG,gBAAgB,SAAS,WAAW;AAAA,YAC5C,IAAI;AAAA,cACF,UAAU,YAAY,cAAc,SAAS;AAAA,cAC7C,WAAW,YAAY,aAAa,SAAS;AAAA,cAC7C,OAAO,YAAY,SAAS,GAAG,OAAO,GAAG,MAAM;AAAA,cAC/C,QAAQ;AAAA,cACR,SAAS;AAAA,cACT,cAAc;AAAA,YAChB;AAAA,YACA,QAAQ,MAAM;AACZ,kBAAI,CAAC,UAAU;AACb,yBAAS;AAAA,cACX;AAAA,YACF;AAAA,YACA,SAAS,MAAM;AACb,uBAAS,sBAAsB;AAC/B,wBAAU,IAAI,MAAM,sBAAsB,CAAC;AAAA,YAC7C;AAAA;AAAA,QACF;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,WAAW,eAAe,SAAS;AAAA,MACnC,IAAI;AAAA,QACF;AAAA,QACA;AAAA,QACA,SAAS;AAAA,QACT,eAAe;AAAA,QACf,UAAU;AAAA,QACV,GAAG;AAAA,MACL;AAAA,MACC,GAAG;AAAA,MAEJ,+BAAC,QAAK,IAAI,EAAE,QAAQ,QAAQ,OAAO,QAAQ,SAAS,QAAQ,eAAe,UAAU,UAAU,SAAS,GAAG,WAAW,GACpH;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,QAAQ,oBAAC,oBAAS,KAAK,eAAe,MAAM,IAAI;AAAA,YAChD,OACE,oBAAC,cAAW,SAAQ,aAAY,YAAY,KACzC,4BACH;AAAA,YAEF,IAAI,EAAE,IAAI,EAAE;AAAA;AAAA,QACd;AAAA,QAGA,oBAAC,OAAI,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,QAAQ,gBAAgB,SAAS,GACjE,+BAAC,SAAM,WAAU,OAAM,SAAS,GAAG,YAAW,UAAS,UAAS,QAAO,KAAK,GAEzE;AAAA,8BACC,iCACE;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS;AAAA,gBACT,UAAU,gBAAgB;AAAA,gBAC1B,OAAM;AAAA,gBACN,cAAW;AAAA,gBAEX,8BAAC,iBAAc,UAAS,SAAQ;AAAA;AAAA,YAClC;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS;AAAA,gBACT,UAAU,gBAAgB;AAAA,gBAC1B,OAAM;AAAA,gBACN,cAAW;AAAA,gBAEX,8BAAC,mBAAgB,UAAS,SAAQ;AAAA;AAAA,YACpC;AAAA,YACA,qBAAC,cAAW,SAAQ,SAAQ,OAAM,kBAAiB,IAAI,EAAE,UAAU,KAAK,WAAW,SAAS,GAAG;AAAA;AAAA,cACvF;AAAA,cAAY;AAAA,cAAK;AAAA,eACzB;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS;AAAA,gBACT,UAAU,gBAAgB;AAAA,gBAC1B,OAAM;AAAA,gBACN,cAAW;AAAA,gBAEX,8BAAC,oBAAiB,UAAS,SAAQ;AAAA;AAAA,YACrC;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS;AAAA,gBACT,UAAU,gBAAgB;AAAA,gBAC1B,OAAM;AAAA,gBACN,cAAW;AAAA,gBAEX,8BAAC,gBAAa,UAAS,SAAQ;AAAA;AAAA,YACjC;AAAA,YACA,oBAAC,WAAQ,aAAY,YAAW,UAAQ,MAAC,IAAI,EAAE,IAAI,EAAE,GAAG;AAAA,aAC1D;AAAA,UAIF;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS;AAAA,cACT,UAAU,CAAC,YAAY,QAAQ;AAAA,cAC/B,OAAM;AAAA,cACN,cAAW;AAAA,cAEX,8BAAC,eAAY,UAAS,SAAQ;AAAA;AAAA,UAChC;AAAA,UACA,oBAAC,cAAW,SAAQ,SAAQ,OAAM,kBAAiB,IAAI,EAAE,UAAU,IAAI,WAAW,SAAS,GACxF,qBAAW,GAAG,YAAY,MAAM,UACnC;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS;AAAA,cACT,UAAU,CAAC,YAAY,QAAQ;AAAA,cAC/B,OAAM;AAAA,cACN,cAAW;AAAA,cAEX,8BAAC,cAAW,UAAS,SAAQ;AAAA;AAAA,UAC/B;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS;AAAA,cACT,UAAU,CAAC;AAAA,cACX,OAAM;AAAA,cACN,cAAW;AAAA,cACX,OAAO,YAAY,cAAc,YAAY;AAAA,cAE7C,8BAAC,mBAAgB,UAAS,SAAQ;AAAA;AAAA,UACpC;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS;AAAA,cACT,UAAU,CAAC;AAAA,cACX,OAAM;AAAA,cACN,cAAW;AAAA,cACX,OAAO,YAAY,aAAa,YAAY;AAAA,cAE5C,8BAAC,iBAAc,UAAS,SAAQ;AAAA;AAAA,UAClC;AAAA,UAEA,oBAAC,WAAQ,aAAY,YAAW,UAAQ,MAAC,IAAI,EAAE,IAAI,EAAE,GAAG;AAAA,UAGvD,CAAC,QAAQ,SAAS,UAAU,KAC3B;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,QAAQ,WAAW,YAAY,eAAe;AAAA,cACvD,UAAU,QAAQ,WAAW,UAAU;AAAA,cACvC,OAAO,QAAQ,SAAS,UAAU,KAAK;AAAA,cACvC,cAAW;AAAA,cAEV,kBAAQ,QAAQ,UAAU,KAAK,oBAAC,gBAAa,UAAS,SAAQ;AAAA;AAAA,UACjE;AAAA,UAGD,CAAC,QAAQ,SAAS,OAAO,KACxB;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,QAAQ,WAAW,SAAS,YAAY;AAAA,cACjD,UAAU,QAAQ,WAAW,OAAO;AAAA,cACpC,OAAO,QAAQ,SAAS,OAAO,KAAK;AAAA,cACpC,cAAW;AAAA,cAEV,kBAAQ,QAAQ,OAAO,KAAK,oBAAC,aAAU,UAAS,SAAQ;AAAA;AAAA,UAC3D;AAAA,UAGD,CAAC,QAAQ,SAAS,YAAY,KAC7B;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,QAAQ,WAAW,cAAc,sBAAsB;AAAA,cAChE,UAAU,QAAQ,WAAW,YAAY;AAAA,cACzC,OAAO,QAAQ,SAAS,YAAY,KAAK;AAAA,cACzC,cAAW;AAAA,cAEV,kBAAQ,QAAQ,YAAY,KAAK,oBAAC,kBAAe,UAAS,SAAQ;AAAA;AAAA,UACrE;AAAA,UAGD,CAAC,QAAQ,SAAS,UAAU,KAC3B;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,QAAQ,WAAW,YAAY,eAAe;AAAA,cACvD,UAAU,QAAQ,WAAW,UAAU;AAAA,cACvC,OAAO,QAAQ,SAAS,UAAU,KAAK;AAAA,cACvC,cAAW;AAAA,cAEV,kBAAQ,QAAQ,UAAU,KAAK,oBAAC,mBAAgB,UAAS,SAAQ;AAAA;AAAA,UACpE;AAAA,UAGD,CAAC,QAAQ,SAAS,YAAY,KAC7B;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,QAAQ,WAAW,cAAc,iBAAiB;AAAA,cAC3D,UAAU,QAAQ,WAAW,YAAY;AAAA,cACzC,OAAO,QAAQ,SAAS,YAAY,KAAK;AAAA,cACzC,cAAW;AAAA,cAEV,kBAAQ,QAAQ,YAAY,KAAK,oBAAC,YAAS,UAAS,SAAQ;AAAA;AAAA,UAC/D;AAAA,WAEJ,GACF;AAAA,SAEE,aAAa,oBAAoB,oBAAC,kBAAe,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,GAAG;AAAA,QACxE,SACC,oBAAC,cAAW,OAAM,SAAQ,SAAQ,SAAQ,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,GAC1D,iBACH;AAAA,QAEF,oBAAC,WAAQ;AAAA,QACT;AAAA,UAAC;AAAA;AAAA,YACC,IAAI;AAAA,cACF,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,WAAW;AAAA,cACX,GAAG;AAAA,cACH,UAAU;AAAA,cACV,iBAAiB;AAAA,cACjB,UAAU;AAAA,YACZ;AAAA,YAEA;AAAA,cAAC;AAAA;AAAA,gBACC,KAAK;AAAA,gBACL,IAAI;AAAA,kBACF,UAAU;AAAA,kBACV,KAAK;AAAA,kBACL,MAAM;AAAA,kBACN,OAAO;AAAA,kBACP,QAAQ;AAAA,kBACR,SAAS;AAAA,kBACT,YAAY;AAAA,kBACZ,gBAAgB;AAAA,kBAChB,GAAG;AAAA,kBACH,UAAU;AAAA,gBACZ;AAAA,gBAEC,sBAAY;AAAA;AAAA,YACf;AAAA;AAAA,QACF;AAAA,SACF;AAAA;AAAA,EACF;AAEJ;AAEO,IAAM,aAAwC,CAAC,UAAU;AAC9D,QAAM,oBAAoB;AAAA,IACxB,MAAM,oBAAoB,MAAM,MAAM,MAAM,UAAU,MAAM,GAAG;AAAA,IAC/D,CAAC,MAAM,MAAM,MAAM,UAAU,MAAM,GAAG;AAAA,EACxC;AAEA,SAAO,oBAAC,qBAAmB,GAAG,OAAO,mBAAsC;AAC7E;","names":["imageUrl","url"]}