@chayns-components/gallery 5.2.4 → 5.2.5

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 (124) hide show
  1. package/AGENTS.md +132 -13
  2. package/lib/cjs/components/Gallery.js +4 -1
  3. package/lib/cjs/components/Gallery.js.map +1 -1
  4. package/lib/cjs/components/Gallery.types.js.map +1 -1
  5. package/lib/cjs/components/gallery-editor/GalleryEditor.constants.js +12 -0
  6. package/lib/cjs/components/gallery-editor/GalleryEditor.constants.js.map +1 -0
  7. package/lib/cjs/components/gallery-editor/GalleryEditor.js +40 -178
  8. package/lib/cjs/components/gallery-editor/GalleryEditor.js.map +1 -1
  9. package/lib/cjs/components/gallery-editor/GalleryEditor.styles.js +3 -1
  10. package/lib/cjs/components/gallery-editor/GalleryEditor.styles.js.map +1 -1
  11. package/lib/cjs/components/gallery-editor/GalleryEditor.types.js.map +1 -1
  12. package/lib/cjs/components/gallery-editor/GalleryEditor.utils.js +27 -0
  13. package/lib/cjs/components/gallery-editor/GalleryEditor.utils.js.map +1 -0
  14. package/lib/cjs/components/gallery-editor/add-file/AddFile.js +1 -1
  15. package/lib/cjs/components/gallery-editor/add-file/AddFile.js.map +1 -1
  16. package/lib/cjs/components/gallery-editor/gallery-editor-item/GalleryEditorItem.js +48 -19
  17. package/lib/cjs/components/gallery-editor/gallery-editor-item/GalleryEditorItem.js.map +1 -1
  18. package/lib/cjs/components/gallery-editor/gallery-editor-item/GalleryEditorItem.styles.js +10 -3
  19. package/lib/cjs/components/gallery-editor/gallery-editor-item/GalleryEditorItem.styles.js.map +1 -1
  20. package/lib/cjs/components/gallery-editor/gallery-editor-item/GalleryEditorItem.types.js.map +1 -1
  21. package/lib/cjs/components/gallery-editor/gallery-editor-item/gallery-editor-media-item/GalleryEditorMediaItem.js +10 -4
  22. package/lib/cjs/components/gallery-editor/gallery-editor-item/gallery-editor-media-item/GalleryEditorMediaItem.js.map +1 -1
  23. package/lib/cjs/components/gallery-editor/gallery-editor-item/gallery-editor-media-item/GalleryEditorMediaItem.types.js.map +1 -1
  24. package/lib/cjs/components/gallery-editor/gallery-editor-item/gallery-editor-preview-item/GalleryEditorPreviewItem.js +7 -10
  25. package/lib/cjs/components/gallery-editor/gallery-editor-item/gallery-editor-preview-item/GalleryEditorPreviewItem.js.map +1 -1
  26. package/lib/cjs/components/gallery-editor/useGalleryEditorState.js +161 -0
  27. package/lib/cjs/components/gallery-editor/useGalleryEditorState.js.map +1 -0
  28. package/lib/cjs/components/gallery-viewer/GalleryViewer.constants.js +8 -0
  29. package/lib/cjs/components/gallery-viewer/GalleryViewer.constants.js.map +1 -0
  30. package/lib/cjs/components/gallery-viewer/GalleryViewer.js +8 -4
  31. package/lib/cjs/components/gallery-viewer/GalleryViewer.js.map +1 -1
  32. package/lib/cjs/components/gallery-viewer/GalleryViewer.types.js.map +1 -1
  33. package/lib/cjs/components/gallery-viewer/gallery-viewer-item/GalleryViewerItem.js +6 -3
  34. package/lib/cjs/components/gallery-viewer/gallery-viewer-item/GalleryViewerItem.js.map +1 -1
  35. package/lib/cjs/components/gallery-viewer/gallery-viewer-item/GalleryViewerItem.types.js.map +1 -1
  36. package/lib/cjs/components/media-content/MediaContent.constants.js +12 -0
  37. package/lib/cjs/components/media-content/MediaContent.constants.js.map +1 -0
  38. package/lib/cjs/components/media-content/MediaContent.js +95 -20
  39. package/lib/cjs/components/media-content/MediaContent.js.map +1 -1
  40. package/lib/cjs/components/media-content/MediaContent.styles.js +35 -5
  41. package/lib/cjs/components/media-content/MediaContent.styles.js.map +1 -1
  42. package/lib/cjs/components/media-content/MediaContent.types.js.map +1 -1
  43. package/lib/cjs/components/media-content/MediaContent.utils.js +84 -0
  44. package/lib/cjs/components/media-content/MediaContent.utils.js.map +1 -0
  45. package/lib/cjs/components/media-content/useMediaContentSize.js +68 -0
  46. package/lib/cjs/components/media-content/useMediaContentSize.js.map +1 -0
  47. package/lib/cjs/utils/gallery.js +2 -2
  48. package/lib/cjs/utils/gallery.js.map +1 -1
  49. package/lib/esm/components/Gallery.js +4 -1
  50. package/lib/esm/components/Gallery.js.map +1 -1
  51. package/lib/esm/components/Gallery.types.js.map +1 -1
  52. package/lib/esm/components/gallery-editor/GalleryEditor.constants.js +6 -0
  53. package/lib/esm/components/gallery-editor/GalleryEditor.constants.js.map +1 -0
  54. package/lib/esm/components/gallery-editor/GalleryEditor.js +37 -174
  55. package/lib/esm/components/gallery-editor/GalleryEditor.js.map +1 -1
  56. package/lib/esm/components/gallery-editor/GalleryEditor.styles.js +3 -1
  57. package/lib/esm/components/gallery-editor/GalleryEditor.styles.js.map +1 -1
  58. package/lib/esm/components/gallery-editor/GalleryEditor.types.js.map +1 -1
  59. package/lib/esm/components/gallery-editor/GalleryEditor.utils.js +17 -0
  60. package/lib/esm/components/gallery-editor/GalleryEditor.utils.js.map +1 -0
  61. package/lib/esm/components/gallery-editor/add-file/AddFile.js +2 -2
  62. package/lib/esm/components/gallery-editor/add-file/AddFile.js.map +1 -1
  63. package/lib/esm/components/gallery-editor/gallery-editor-item/GalleryEditorItem.js +47 -19
  64. package/lib/esm/components/gallery-editor/gallery-editor-item/GalleryEditorItem.js.map +1 -1
  65. package/lib/esm/components/gallery-editor/gallery-editor-item/GalleryEditorItem.styles.js +9 -2
  66. package/lib/esm/components/gallery-editor/gallery-editor-item/GalleryEditorItem.styles.js.map +1 -1
  67. package/lib/esm/components/gallery-editor/gallery-editor-item/GalleryEditorItem.types.js.map +1 -1
  68. package/lib/esm/components/gallery-editor/gallery-editor-item/gallery-editor-media-item/GalleryEditorMediaItem.js +9 -4
  69. package/lib/esm/components/gallery-editor/gallery-editor-item/gallery-editor-media-item/GalleryEditorMediaItem.js.map +1 -1
  70. package/lib/esm/components/gallery-editor/gallery-editor-item/gallery-editor-media-item/GalleryEditorMediaItem.types.js.map +1 -1
  71. package/lib/esm/components/gallery-editor/gallery-editor-item/gallery-editor-preview-item/GalleryEditorPreviewItem.js +6 -9
  72. package/lib/esm/components/gallery-editor/gallery-editor-item/gallery-editor-preview-item/GalleryEditorPreviewItem.js.map +1 -1
  73. package/lib/esm/components/gallery-editor/useGalleryEditorState.js +150 -0
  74. package/lib/esm/components/gallery-editor/useGalleryEditorState.js.map +1 -0
  75. package/lib/esm/components/gallery-viewer/GalleryViewer.constants.js +2 -0
  76. package/lib/esm/components/gallery-viewer/GalleryViewer.constants.js.map +1 -0
  77. package/lib/esm/components/gallery-viewer/GalleryViewer.js +9 -5
  78. package/lib/esm/components/gallery-viewer/GalleryViewer.js.map +1 -1
  79. package/lib/esm/components/gallery-viewer/GalleryViewer.types.js.map +1 -1
  80. package/lib/esm/components/gallery-viewer/gallery-viewer-item/GalleryViewerItem.js +5 -3
  81. package/lib/esm/components/gallery-viewer/gallery-viewer-item/GalleryViewerItem.js.map +1 -1
  82. package/lib/esm/components/gallery-viewer/gallery-viewer-item/GalleryViewerItem.types.js.map +1 -1
  83. package/lib/esm/components/media-content/MediaContent.constants.js +6 -0
  84. package/lib/esm/components/media-content/MediaContent.constants.js.map +1 -0
  85. package/lib/esm/components/media-content/MediaContent.js +94 -21
  86. package/lib/esm/components/media-content/MediaContent.js.map +1 -1
  87. package/lib/esm/components/media-content/MediaContent.styles.js +34 -4
  88. package/lib/esm/components/media-content/MediaContent.styles.js.map +1 -1
  89. package/lib/esm/components/media-content/MediaContent.types.js.map +1 -1
  90. package/lib/esm/components/media-content/MediaContent.utils.js +71 -0
  91. package/lib/esm/components/media-content/MediaContent.utils.js.map +1 -0
  92. package/lib/esm/components/media-content/useMediaContentSize.js +62 -0
  93. package/lib/esm/components/media-content/useMediaContentSize.js.map +1 -0
  94. package/lib/esm/utils/gallery.js +2 -2
  95. package/lib/esm/utils/gallery.js.map +1 -1
  96. package/lib/types/components/Gallery.types.d.ts +12 -0
  97. package/lib/types/components/gallery-editor/GalleryEditor.constants.d.ts +5 -0
  98. package/lib/types/components/gallery-editor/GalleryEditor.styles.d.ts +7 -3
  99. package/lib/types/components/gallery-editor/GalleryEditor.types.d.ts +11 -0
  100. package/lib/types/components/gallery-editor/GalleryEditor.utils.d.ts +5 -0
  101. package/lib/types/components/gallery-editor/add-file/AddFile.d.ts +3 -3
  102. package/lib/types/components/gallery-editor/add-file/AddFile.styles.d.ts +5 -3
  103. package/lib/types/components/gallery-editor/gallery-editor-item/GalleryEditorItem.d.ts +3 -3
  104. package/lib/types/components/gallery-editor/gallery-editor-item/GalleryEditorItem.styles.d.ts +13 -3
  105. package/lib/types/components/gallery-editor/gallery-editor-item/GalleryEditorItem.types.d.ts +8 -0
  106. package/lib/types/components/gallery-editor/gallery-editor-item/gallery-editor-media-item/GalleryEditorMediaItem.d.ts +3 -3
  107. package/lib/types/components/gallery-editor/gallery-editor-item/gallery-editor-media-item/GalleryEditorMediaItem.styles.d.ts +3 -1
  108. package/lib/types/components/gallery-editor/gallery-editor-item/gallery-editor-media-item/GalleryEditorMediaItem.types.d.ts +15 -0
  109. package/lib/types/components/gallery-editor/gallery-editor-item/gallery-editor-preview-item/GalleryEditorPreviewItem.d.ts +3 -3
  110. package/lib/types/components/gallery-editor/gallery-editor-item/gallery-editor-preview-item/GalleryEditorPreviewItem.styles.d.ts +12 -6
  111. package/lib/types/components/gallery-editor/useGalleryEditorState.d.ts +21 -0
  112. package/lib/types/components/gallery-viewer/GalleryViewer.constants.d.ts +1 -0
  113. package/lib/types/components/gallery-viewer/GalleryViewer.styles.d.ts +7 -3
  114. package/lib/types/components/gallery-viewer/GalleryViewer.types.d.ts +11 -0
  115. package/lib/types/components/gallery-viewer/gallery-viewer-item/GalleryViewerItem.d.ts +3 -3
  116. package/lib/types/components/gallery-viewer/gallery-viewer-item/GalleryViewerItem.styles.d.ts +2 -2
  117. package/lib/types/components/gallery-viewer/gallery-viewer-item/GalleryViewerItem.types.d.ts +8 -0
  118. package/lib/types/components/media-content/MediaContent.constants.d.ts +5 -0
  119. package/lib/types/components/media-content/MediaContent.d.ts +3 -3
  120. package/lib/types/components/media-content/MediaContent.styles.d.ts +50 -9
  121. package/lib/types/components/media-content/MediaContent.types.d.ts +16 -0
  122. package/lib/types/components/media-content/MediaContent.utils.d.ts +12 -0
  123. package/lib/types/components/media-content/useMediaContentSize.d.ts +3 -0
  124. package/package.json +4 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGalleryEditorState.js","names":["uploadFile","createDialog","DialogType","useCallback","useEffect","useMemo","useState","v4","uuidv4","filterDuplicateFile","generatePreviewUrl","generateVideoThumbnail","openFiles","getPendingPreviewFileItems","getPendingUploadFileItems","mapExternalFilesIntoInternalItems","mergeExternalFilesWithInternalState","useGalleryEditorState","allowDragAndDrop","doubleFileDialogMessage","files","maxFiles","onAdd","onFileCountChange","onRemove","fileItems","setFileItems","callDuplicateFileDialog","type","ALERT","text","handlePreviewUrlCallback","previewUrl","file","prevState","map","prevFile","id","handleUploadFileCallback","uploadedFile","duplicateItem","find","url","updatedState","undefined","state","filter","Boolean","filesToGeneratePreview","filesToUpload","handleAddFiles","filesToAdd","newFileItems","forEach","newFile","push","limitedFileItems","slice","Math","max","length","handleDeleteFile","handleDrop","event","preventDefault","Array","from","dataTransfer","handleOpenFiles","handleClear","includes","callback","fileToUpload","externalFileItems"],"sources":["../../../../src/components/gallery-editor/useGalleryEditorState.ts"],"sourcesContent":["import {\n Image,\n uploadFile,\n Video,\n type FileItem,\n type InternalFileItem,\n} from '@chayns-components/core';\nimport { createDialog, DialogType } from 'chayns-api';\nimport { type DragEvent, useCallback, useEffect, useMemo, useState } from 'react';\nimport { v4 as uuidv4 } from 'uuid';\nimport { filterDuplicateFile, generatePreviewUrl, generateVideoThumbnail } from '../../utils/file';\nimport { openFiles } from '../../utils/gallery';\nimport {\n getPendingPreviewFileItems,\n getPendingUploadFileItems,\n mapExternalFilesIntoInternalItems,\n mergeExternalFilesWithInternalState,\n} from './GalleryEditor.utils';\n\ntype UseGalleryEditorStateOptions = {\n allowDragAndDrop: boolean;\n doubleFileDialogMessage: string;\n files?: FileItem[];\n maxFiles?: number;\n onAdd?: (file: FileItem) => void;\n onFileCountChange?: (fileCount: number) => void;\n onRemove?: (file: FileItem) => void;\n};\n\ntype GalleryEditorStateResult = {\n fileItems: InternalFileItem[];\n handleAddFiles: (filesToAdd: File[]) => void;\n handleClear: () => void;\n handleDeleteFile: (id?: string) => void;\n handleDrop: (event: DragEvent<HTMLDivElement>) => void;\n handleOpenFiles: (file: InternalFileItem) => void;\n};\n\nconst useGalleryEditorState = ({\n allowDragAndDrop,\n doubleFileDialogMessage,\n files,\n maxFiles,\n onAdd,\n onFileCountChange,\n onRemove,\n}: UseGalleryEditorStateOptions): GalleryEditorStateResult => {\n const [fileItems, setFileItems] = useState<InternalFileItem[]>(() =>\n mapExternalFilesIntoInternalItems(files),\n );\n\n const callDuplicateFileDialog = useCallback(() => {\n createDialog({ type: DialogType.ALERT, text: doubleFileDialogMessage });\n }, [doubleFileDialogMessage]);\n\n const handlePreviewUrlCallback = useCallback((previewUrl: string, file: InternalFileItem) => {\n setFileItems((prevState) =>\n prevState.map((prevFile) =>\n prevFile.id === file.id ? { ...prevFile, previewUrl } : prevFile,\n ),\n );\n }, []);\n\n const handleUploadFileCallback = useCallback(\n (file: InternalFileItem, uploadedFile: Video | Image) => {\n setFileItems((prevState) => {\n const duplicateItem = prevState.find(\n (prevFile) => prevFile.uploadedFile?.url === uploadedFile.url,\n );\n\n const updatedState = prevState.map((prevFile) => {\n if (prevFile.uploadedFile?.url === uploadedFile.url) {\n callDuplicateFileDialog();\n\n return undefined;\n }\n\n if (prevFile.id === file.id) {\n if (typeof onAdd === 'function' && !duplicateItem) {\n onAdd({ file: uploadedFile, id: file.id });\n }\n\n return {\n ...prevFile,\n uploadedFile,\n state: 'uploaded',\n };\n }\n\n return prevFile;\n });\n\n return updatedState.filter(Boolean) as InternalFileItem[];\n });\n },\n [callDuplicateFileDialog, onAdd],\n );\n\n const filesToGeneratePreview = useMemo(\n () => getPendingPreviewFileItems(fileItems),\n [fileItems],\n );\n const filesToUpload = useMemo(() => getPendingUploadFileItems(fileItems), [fileItems]);\n\n const handleAddFiles = useCallback(\n (filesToAdd: File[]) => {\n setFileItems((prevState) => {\n const newFileItems: InternalFileItem[] = [];\n\n filesToAdd.forEach((file) => {\n if (file && !filterDuplicateFile({ files: prevState, newFile: file })) {\n newFileItems.push({\n id: uuidv4(),\n file,\n state: 'none',\n });\n }\n });\n\n const limitedFileItems = maxFiles\n ? newFileItems.slice(0, Math.max(maxFiles - prevState.length, 0))\n : newFileItems;\n\n return [...prevState, ...limitedFileItems];\n });\n },\n [maxFiles],\n );\n\n const handleDeleteFile = useCallback(\n (id?: string) => {\n let uploadedFile: Image | Video | undefined;\n\n setFileItems((prevState) => {\n uploadedFile = prevState.find((file) => file.id === id)?.uploadedFile;\n\n return prevState.filter((file) => file.id !== id);\n });\n\n if (uploadedFile && typeof onRemove === 'function') {\n onRemove({ file: uploadedFile, id });\n }\n },\n [onRemove],\n );\n\n const handleDrop = useCallback(\n (event: DragEvent<HTMLDivElement>) => {\n if (!allowDragAndDrop) {\n return;\n }\n\n event.preventDefault();\n\n handleAddFiles(Array.from(event.dataTransfer.files));\n },\n [allowDragAndDrop, handleAddFiles],\n );\n\n const handleOpenFiles = useCallback(\n (file: InternalFileItem) => {\n openFiles(fileItems, file);\n },\n [fileItems],\n );\n\n const handleClear = useCallback(() => {\n setFileItems([]);\n }, []);\n\n useEffect(() => {\n if (typeof onFileCountChange === 'function') {\n onFileCountChange(fileItems.length);\n }\n }, [fileItems.length, onFileCountChange]);\n\n useEffect(() => {\n filesToGeneratePreview.forEach((file) => {\n if (!file.file) {\n return;\n }\n\n if (file.file.type.includes('video/')) {\n generateVideoThumbnail({\n file: file.file,\n callback: (previewUrl) => handlePreviewUrlCallback(previewUrl, file),\n });\n\n return;\n }\n\n generatePreviewUrl({\n file: file.file,\n callback: (previewUrl) => handlePreviewUrlCallback(previewUrl, file),\n });\n });\n\n filesToUpload.forEach((file) => {\n setFileItems((prevState) =>\n prevState.map((prevFile) =>\n prevFile.id === file.id ? { ...prevFile, state: 'uploading' } : prevFile,\n ),\n );\n\n void uploadFile({\n fileToUpload: file,\n callback: (uploadedFile) => handleUploadFileCallback(file, uploadedFile),\n });\n });\n }, [filesToGeneratePreview, filesToUpload, handlePreviewUrlCallback, handleUploadFileCallback]);\n\n useEffect(() => {\n const externalFileItems = mapExternalFilesIntoInternalItems(files);\n\n setFileItems((prevState) =>\n mergeExternalFilesWithInternalState(prevState, externalFileItems),\n );\n }, [files]);\n\n return {\n fileItems,\n handleAddFiles,\n handleClear,\n handleDeleteFile,\n handleDrop,\n handleOpenFiles,\n };\n};\n\nexport default useGalleryEditorState;\n"],"mappings":"AAAA,SAEIA,UAAU,QAIP,yBAAyB;AAChC,SAASC,YAAY,EAAEC,UAAU,QAAQ,YAAY;AACrD,SAAyBC,WAAW,EAAEC,SAAS,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,OAAO;AACjF,SAASC,EAAE,IAAIC,MAAM,QAAQ,MAAM;AACnC,SAASC,mBAAmB,EAAEC,kBAAkB,EAAEC,sBAAsB,QAAQ,kBAAkB;AAClG,SAASC,SAAS,QAAQ,qBAAqB;AAC/C,SACIC,0BAA0B,EAC1BC,yBAAyB,EACzBC,iCAAiC,EACjCC,mCAAmC,QAChC,uBAAuB;AAqB9B,MAAMC,qBAAqB,GAAGA,CAAC;EAC3BC,gBAAgB;EAChBC,uBAAuB;EACvBC,KAAK;EACLC,QAAQ;EACRC,KAAK;EACLC,iBAAiB;EACjBC;AAC0B,CAAC,KAA+B;EAC1D,MAAM,CAACC,SAAS,EAAEC,YAAY,CAAC,GAAGpB,QAAQ,CAAqB,MAC3DS,iCAAiC,CAACK,KAAK,CAC3C,CAAC;EAED,MAAMO,uBAAuB,GAAGxB,WAAW,CAAC,MAAM;IAC9CF,YAAY,CAAC;MAAE2B,IAAI,EAAE1B,UAAU,CAAC2B,KAAK;MAAEC,IAAI,EAAEX;IAAwB,CAAC,CAAC;EAC3E,CAAC,EAAE,CAACA,uBAAuB,CAAC,CAAC;EAE7B,MAAMY,wBAAwB,GAAG5B,WAAW,CAAC,CAAC6B,UAAkB,EAAEC,IAAsB,KAAK;IACzFP,YAAY,CAAEQ,SAAS,IACnBA,SAAS,CAACC,GAAG,CAAEC,QAAQ,IACnBA,QAAQ,CAACC,EAAE,KAAKJ,IAAI,CAACI,EAAE,GAAG;MAAE,GAAGD,QAAQ;MAAEJ;IAAW,CAAC,GAAGI,QAC5D,CACJ,CAAC;EACL,CAAC,EAAE,EAAE,CAAC;EAEN,MAAME,wBAAwB,GAAGnC,WAAW,CACxC,CAAC8B,IAAsB,EAAEM,YAA2B,KAAK;IACrDb,YAAY,CAAEQ,SAAS,IAAK;MACxB,MAAMM,aAAa,GAAGN,SAAS,CAACO,IAAI,CAC/BL,QAAQ,IAAKA,QAAQ,CAACG,YAAY,EAAEG,GAAG,KAAKH,YAAY,CAACG,GAC9D,CAAC;MAED,MAAMC,YAAY,GAAGT,SAAS,CAACC,GAAG,CAAEC,QAAQ,IAAK;QAC7C,IAAIA,QAAQ,CAACG,YAAY,EAAEG,GAAG,KAAKH,YAAY,CAACG,GAAG,EAAE;UACjDf,uBAAuB,CAAC,CAAC;UAEzB,OAAOiB,SAAS;QACpB;QAEA,IAAIR,QAAQ,CAACC,EAAE,KAAKJ,IAAI,CAACI,EAAE,EAAE;UACzB,IAAI,OAAOf,KAAK,KAAK,UAAU,IAAI,CAACkB,aAAa,EAAE;YAC/ClB,KAAK,CAAC;cAAEW,IAAI,EAAEM,YAAY;cAAEF,EAAE,EAAEJ,IAAI,CAACI;YAAG,CAAC,CAAC;UAC9C;UAEA,OAAO;YACH,GAAGD,QAAQ;YACXG,YAAY;YACZM,KAAK,EAAE;UACX,CAAC;QACL;QAEA,OAAOT,QAAQ;MACnB,CAAC,CAAC;MAEF,OAAOO,YAAY,CAACG,MAAM,CAACC,OAAO,CAAC;IACvC,CAAC,CAAC;EACN,CAAC,EACD,CAACpB,uBAAuB,EAAEL,KAAK,CACnC,CAAC;EAED,MAAM0B,sBAAsB,GAAG3C,OAAO,CAClC,MAAMQ,0BAA0B,CAACY,SAAS,CAAC,EAC3C,CAACA,SAAS,CACd,CAAC;EACD,MAAMwB,aAAa,GAAG5C,OAAO,CAAC,MAAMS,yBAAyB,CAACW,SAAS,CAAC,EAAE,CAACA,SAAS,CAAC,CAAC;EAEtF,MAAMyB,cAAc,GAAG/C,WAAW,CAC7BgD,UAAkB,IAAK;IACpBzB,YAAY,CAAEQ,SAAS,IAAK;MACxB,MAAMkB,YAAgC,GAAG,EAAE;MAE3CD,UAAU,CAACE,OAAO,CAAEpB,IAAI,IAAK;QACzB,IAAIA,IAAI,IAAI,CAACxB,mBAAmB,CAAC;UAAEW,KAAK,EAAEc,SAAS;UAAEoB,OAAO,EAAErB;QAAK,CAAC,CAAC,EAAE;UACnEmB,YAAY,CAACG,IAAI,CAAC;YACdlB,EAAE,EAAE7B,MAAM,CAAC,CAAC;YACZyB,IAAI;YACJY,KAAK,EAAE;UACX,CAAC,CAAC;QACN;MACJ,CAAC,CAAC;MAEF,MAAMW,gBAAgB,GAAGnC,QAAQ,GAC3B+B,YAAY,CAACK,KAAK,CAAC,CAAC,EAAEC,IAAI,CAACC,GAAG,CAACtC,QAAQ,GAAGa,SAAS,CAAC0B,MAAM,EAAE,CAAC,CAAC,CAAC,GAC/DR,YAAY;MAElB,OAAO,CAAC,GAAGlB,SAAS,EAAE,GAAGsB,gBAAgB,CAAC;IAC9C,CAAC,CAAC;EACN,CAAC,EACD,CAACnC,QAAQ,CACb,CAAC;EAED,MAAMwC,gBAAgB,GAAG1D,WAAW,CAC/BkC,EAAW,IAAK;IACb,IAAIE,YAAuC;IAE3Cb,YAAY,CAAEQ,SAAS,IAAK;MACxBK,YAAY,GAAGL,SAAS,CAACO,IAAI,CAAER,IAAI,IAAKA,IAAI,CAACI,EAAE,KAAKA,EAAE,CAAC,EAAEE,YAAY;MAErE,OAAOL,SAAS,CAACY,MAAM,CAAEb,IAAI,IAAKA,IAAI,CAACI,EAAE,KAAKA,EAAE,CAAC;IACrD,CAAC,CAAC;IAEF,IAAIE,YAAY,IAAI,OAAOf,QAAQ,KAAK,UAAU,EAAE;MAChDA,QAAQ,CAAC;QAAES,IAAI,EAAEM,YAAY;QAAEF;MAAG,CAAC,CAAC;IACxC;EACJ,CAAC,EACD,CAACb,QAAQ,CACb,CAAC;EAED,MAAMsC,UAAU,GAAG3D,WAAW,CACzB4D,KAAgC,IAAK;IAClC,IAAI,CAAC7C,gBAAgB,EAAE;MACnB;IACJ;IAEA6C,KAAK,CAACC,cAAc,CAAC,CAAC;IAEtBd,cAAc,CAACe,KAAK,CAACC,IAAI,CAACH,KAAK,CAACI,YAAY,CAAC/C,KAAK,CAAC,CAAC;EACxD,CAAC,EACD,CAACF,gBAAgB,EAAEgC,cAAc,CACrC,CAAC;EAED,MAAMkB,eAAe,GAAGjE,WAAW,CAC9B8B,IAAsB,IAAK;IACxBrB,SAAS,CAACa,SAAS,EAAEQ,IAAI,CAAC;EAC9B,CAAC,EACD,CAACR,SAAS,CACd,CAAC;EAED,MAAM4C,WAAW,GAAGlE,WAAW,CAAC,MAAM;IAClCuB,YAAY,CAAC,EAAE,CAAC;EACpB,CAAC,EAAE,EAAE,CAAC;EAENtB,SAAS,CAAC,MAAM;IACZ,IAAI,OAAOmB,iBAAiB,KAAK,UAAU,EAAE;MACzCA,iBAAiB,CAACE,SAAS,CAACmC,MAAM,CAAC;IACvC;EACJ,CAAC,EAAE,CAACnC,SAAS,CAACmC,MAAM,EAAErC,iBAAiB,CAAC,CAAC;EAEzCnB,SAAS,CAAC,MAAM;IACZ4C,sBAAsB,CAACK,OAAO,CAAEpB,IAAI,IAAK;MACrC,IAAI,CAACA,IAAI,CAACA,IAAI,EAAE;QACZ;MACJ;MAEA,IAAIA,IAAI,CAACA,IAAI,CAACL,IAAI,CAAC0C,QAAQ,CAAC,QAAQ,CAAC,EAAE;QACnC3D,sBAAsB,CAAC;UACnBsB,IAAI,EAAEA,IAAI,CAACA,IAAI;UACfsC,QAAQ,EAAGvC,UAAU,IAAKD,wBAAwB,CAACC,UAAU,EAAEC,IAAI;QACvE,CAAC,CAAC;QAEF;MACJ;MAEAvB,kBAAkB,CAAC;QACfuB,IAAI,EAAEA,IAAI,CAACA,IAAI;QACfsC,QAAQ,EAAGvC,UAAU,IAAKD,wBAAwB,CAACC,UAAU,EAAEC,IAAI;MACvE,CAAC,CAAC;IACN,CAAC,CAAC;IAEFgB,aAAa,CAACI,OAAO,CAAEpB,IAAI,IAAK;MAC5BP,YAAY,CAAEQ,SAAS,IACnBA,SAAS,CAACC,GAAG,CAAEC,QAAQ,IACnBA,QAAQ,CAACC,EAAE,KAAKJ,IAAI,CAACI,EAAE,GAAG;QAAE,GAAGD,QAAQ;QAAES,KAAK,EAAE;MAAY,CAAC,GAAGT,QACpE,CACJ,CAAC;MAED,KAAKpC,UAAU,CAAC;QACZwE,YAAY,EAAEvC,IAAI;QAClBsC,QAAQ,EAAGhC,YAAY,IAAKD,wBAAwB,CAACL,IAAI,EAAEM,YAAY;MAC3E,CAAC,CAAC;IACN,CAAC,CAAC;EACN,CAAC,EAAE,CAACS,sBAAsB,EAAEC,aAAa,EAAElB,wBAAwB,EAAEO,wBAAwB,CAAC,CAAC;EAE/FlC,SAAS,CAAC,MAAM;IACZ,MAAMqE,iBAAiB,GAAG1D,iCAAiC,CAACK,KAAK,CAAC;IAElEM,YAAY,CAAEQ,SAAS,IACnBlB,mCAAmC,CAACkB,SAAS,EAAEuC,iBAAiB,CACpE,CAAC;EACL,CAAC,EAAE,CAACrD,KAAK,CAAC,CAAC;EAEX,OAAO;IACHK,SAAS;IACTyB,cAAc;IACdmB,WAAW;IACXR,gBAAgB;IAChBC,UAAU;IACVM;EACJ,CAAC;AACL,CAAC;AAED,eAAenD,qBAAqB","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+ export const GALLERY_VIEWER_MAX_VISIBLE_ITEMS = 4;
2
+ //# sourceMappingURL=GalleryViewer.constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GalleryViewer.constants.js","names":["GALLERY_VIEWER_MAX_VISIBLE_ITEMS"],"sources":["../../../../src/components/gallery-viewer/GalleryViewer.constants.ts"],"sourcesContent":["export const GALLERY_VIEWER_MAX_VISIBLE_ITEMS = 4;\n"],"mappings":"AAAA,OAAO,MAAMA,gCAAgC,GAAG,CAAC","ignoreList":[]}
@@ -1,18 +1,21 @@
1
- import React, { useCallback, useMemo } from 'react';
1
+ import React, { useCallback } from 'react';
2
2
  import GalleryViewerItem from './gallery-viewer-item/GalleryViewerItem';
3
3
  import { StyledGalleryViewer, StyledGalleryViewerItemWrapper } from './GalleryViewer.styles';
4
4
  import { getGalleryRatio, getGalleryViewerKey, getReadOnlyItemRatio, openKnownFiles } from '../../utils/gallery';
5
5
  import { GalleryViewMode } from '../../types/gallery';
6
+ import { GALLERY_VIEWER_MAX_VISIBLE_ITEMS } from './GalleryViewer.constants';
7
+ const EMPTY_FILE_ITEMS = [];
6
8
  const GalleryViewer = ({
7
9
  files,
10
+ shouldLoadImages = true,
8
11
  viewMode = GalleryViewMode.GRID
9
12
  }) => {
10
- const fileItems = files ?? [];
11
- const ratio = useMemo(() => getGalleryRatio(fileItems), [fileItems]);
13
+ const fileItems = files ?? EMPTY_FILE_ITEMS;
14
+ const ratio = getGalleryRatio(fileItems);
12
15
  const handleOpenFiles = useCallback(file => {
13
16
  openKnownFiles(fileItems, file);
14
17
  }, [fileItems]);
15
- const visibleItems = fileItems.slice(0, 4);
18
+ const visibleItems = fileItems.slice(0, GALLERY_VIEWER_MAX_VISIBLE_ITEMS);
16
19
  return /*#__PURE__*/React.createElement(StyledGalleryViewer, null, /*#__PURE__*/React.createElement(StyledGalleryViewerItemWrapper, {
17
20
  $ratio: ratio,
18
21
  $itemCount: fileItems.length,
@@ -26,7 +29,8 @@ const GalleryViewer = ({
26
29
  index,
27
30
  viewMode
28
31
  }),
29
- remainingItemsLength: fileItems.length > 4 && index === 3 ? fileItems.length : undefined
32
+ shouldLoadImages: shouldLoadImages,
33
+ remainingItemsLength: fileItems.length > GALLERY_VIEWER_MAX_VISIBLE_ITEMS && index === 3 ? fileItems.length : undefined
30
34
  }))));
31
35
  };
32
36
  GalleryViewer.displayName = 'GalleryViewer';
@@ -1 +1 @@
1
- {"version":3,"file":"GalleryViewer.js","names":["React","useCallback","useMemo","GalleryViewerItem","StyledGalleryViewer","StyledGalleryViewerItemWrapper","getGalleryRatio","getGalleryViewerKey","getReadOnlyItemRatio","openKnownFiles","GalleryViewMode","GalleryViewer","files","viewMode","GRID","fileItems","ratio","handleOpenFiles","file","visibleItems","slice","createElement","$ratio","$itemCount","length","$viewMode","map","index","key","fileItem","onClick","remainingItemsLength","undefined","displayName"],"sources":["../../../../src/components/gallery-viewer/GalleryViewer.tsx"],"sourcesContent":["import type { FileItem } from '@chayns-components/core';\nimport React, { FC, useCallback, useMemo } from 'react';\nimport GalleryViewerItem from './gallery-viewer-item/GalleryViewerItem';\nimport { StyledGalleryViewer, StyledGalleryViewerItemWrapper } from './GalleryViewer.styles';\nimport type { GalleryViewerProps } from './GalleryViewer.types';\nimport {\n getGalleryRatio,\n getGalleryViewerKey,\n getReadOnlyItemRatio,\n openKnownFiles,\n} from '../../utils/gallery';\nimport { GalleryViewMode } from '../../types/gallery';\n\nconst GalleryViewer: FC<GalleryViewerProps> = ({ files, viewMode = GalleryViewMode.GRID }) => {\n const fileItems = files ?? [];\n\n const ratio = useMemo(() => getGalleryRatio(fileItems), [fileItems]);\n\n const handleOpenFiles = useCallback(\n (file: FileItem) => {\n openKnownFiles(fileItems, file);\n },\n [fileItems],\n );\n\n const visibleItems = fileItems.slice(0, 4);\n\n return (\n <StyledGalleryViewer>\n <StyledGalleryViewerItemWrapper\n $ratio={ratio}\n $itemCount={fileItems.length}\n $viewMode={viewMode}\n >\n {visibleItems.map((file, index) => (\n <GalleryViewerItem\n key={getGalleryViewerKey(file, index)}\n fileItem={file}\n onClick={handleOpenFiles}\n ratio={getReadOnlyItemRatio({ fileItems, index, viewMode })}\n remainingItemsLength={\n fileItems.length > 4 && index === 3 ? fileItems.length : undefined\n }\n />\n ))}\n </StyledGalleryViewerItemWrapper>\n </StyledGalleryViewer>\n );\n};\n\nGalleryViewer.displayName = 'GalleryViewer';\n\nexport default GalleryViewer;\n"],"mappings":"AACA,OAAOA,KAAK,IAAQC,WAAW,EAAEC,OAAO,QAAQ,OAAO;AACvD,OAAOC,iBAAiB,MAAM,yCAAyC;AACvE,SAASC,mBAAmB,EAAEC,8BAA8B,QAAQ,wBAAwB;AAE5F,SACIC,eAAe,EACfC,mBAAmB,EACnBC,oBAAoB,EACpBC,cAAc,QACX,qBAAqB;AAC5B,SAASC,eAAe,QAAQ,qBAAqB;AAErD,MAAMC,aAAqC,GAAGA,CAAC;EAAEC,KAAK;EAAEC,QAAQ,GAAGH,eAAe,CAACI;AAAK,CAAC,KAAK;EAC1F,MAAMC,SAAS,GAAGH,KAAK,IAAI,EAAE;EAE7B,MAAMI,KAAK,GAAGd,OAAO,CAAC,MAAMI,eAAe,CAACS,SAAS,CAAC,EAAE,CAACA,SAAS,CAAC,CAAC;EAEpE,MAAME,eAAe,GAAGhB,WAAW,CAC9BiB,IAAc,IAAK;IAChBT,cAAc,CAACM,SAAS,EAAEG,IAAI,CAAC;EACnC,CAAC,EACD,CAACH,SAAS,CACd,CAAC;EAED,MAAMI,YAAY,GAAGJ,SAAS,CAACK,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;EAE1C,oBACIpB,KAAA,CAAAqB,aAAA,CAACjB,mBAAmB,qBAChBJ,KAAA,CAAAqB,aAAA,CAAChB,8BAA8B;IAC3BiB,MAAM,EAAEN,KAAM;IACdO,UAAU,EAAER,SAAS,CAACS,MAAO;IAC7BC,SAAS,EAAEZ;EAAS,GAEnBM,YAAY,CAACO,GAAG,CAAC,CAACR,IAAI,EAAES,KAAK,kBAC1B3B,KAAA,CAAAqB,aAAA,CAAClB,iBAAiB;IACdyB,GAAG,EAAErB,mBAAmB,CAACW,IAAI,EAAES,KAAK,CAAE;IACtCE,QAAQ,EAAEX,IAAK;IACfY,OAAO,EAAEb,eAAgB;IACzBD,KAAK,EAAER,oBAAoB,CAAC;MAAEO,SAAS;MAAEY,KAAK;MAAEd;IAAS,CAAC,CAAE;IAC5DkB,oBAAoB,EAChBhB,SAAS,CAACS,MAAM,GAAG,CAAC,IAAIG,KAAK,KAAK,CAAC,GAAGZ,SAAS,CAACS,MAAM,GAAGQ;EAC5D,CACJ,CACJ,CAC2B,CACf,CAAC;AAE9B,CAAC;AAEDrB,aAAa,CAACsB,WAAW,GAAG,eAAe;AAE3C,eAAetB,aAAa","ignoreList":[]}
1
+ {"version":3,"file":"GalleryViewer.js","names":["React","useCallback","GalleryViewerItem","StyledGalleryViewer","StyledGalleryViewerItemWrapper","getGalleryRatio","getGalleryViewerKey","getReadOnlyItemRatio","openKnownFiles","GalleryViewMode","GALLERY_VIEWER_MAX_VISIBLE_ITEMS","EMPTY_FILE_ITEMS","GalleryViewer","files","shouldLoadImages","viewMode","GRID","fileItems","ratio","handleOpenFiles","file","visibleItems","slice","createElement","$ratio","$itemCount","length","$viewMode","map","index","key","fileItem","onClick","remainingItemsLength","undefined","displayName"],"sources":["../../../../src/components/gallery-viewer/GalleryViewer.tsx"],"sourcesContent":["import type { FileItem } from '@chayns-components/core';\nimport React, { FC, useCallback } from 'react';\nimport GalleryViewerItem from './gallery-viewer-item/GalleryViewerItem';\nimport { StyledGalleryViewer, StyledGalleryViewerItemWrapper } from './GalleryViewer.styles';\nimport type { GalleryViewerProps } from './GalleryViewer.types';\nimport {\n getGalleryRatio,\n getGalleryViewerKey,\n getReadOnlyItemRatio,\n openKnownFiles,\n} from '../../utils/gallery';\nimport { GalleryViewMode } from '../../types/gallery';\nimport { GALLERY_VIEWER_MAX_VISIBLE_ITEMS } from './GalleryViewer.constants';\n\nconst EMPTY_FILE_ITEMS: FileItem[] = [];\n\nconst GalleryViewer: FC<GalleryViewerProps> = ({\n files,\n shouldLoadImages = true,\n viewMode = GalleryViewMode.GRID,\n}) => {\n const fileItems = files ?? EMPTY_FILE_ITEMS;\n const ratio = getGalleryRatio(fileItems);\n\n const handleOpenFiles = useCallback(\n (file: FileItem) => {\n openKnownFiles(fileItems, file);\n },\n [fileItems],\n );\n\n const visibleItems = fileItems.slice(0, GALLERY_VIEWER_MAX_VISIBLE_ITEMS);\n\n return (\n <StyledGalleryViewer>\n <StyledGalleryViewerItemWrapper\n $ratio={ratio}\n $itemCount={fileItems.length}\n $viewMode={viewMode}\n >\n {visibleItems.map((file, index) => (\n <GalleryViewerItem\n key={getGalleryViewerKey(file, index)}\n fileItem={file}\n onClick={handleOpenFiles}\n ratio={getReadOnlyItemRatio({ fileItems, index, viewMode })}\n shouldLoadImages={shouldLoadImages}\n remainingItemsLength={\n fileItems.length > GALLERY_VIEWER_MAX_VISIBLE_ITEMS && index === 3\n ? fileItems.length\n : undefined\n }\n />\n ))}\n </StyledGalleryViewerItemWrapper>\n </StyledGalleryViewer>\n );\n};\n\nGalleryViewer.displayName = 'GalleryViewer';\n\nexport default GalleryViewer;\n"],"mappings":"AACA,OAAOA,KAAK,IAAQC,WAAW,QAAQ,OAAO;AAC9C,OAAOC,iBAAiB,MAAM,yCAAyC;AACvE,SAASC,mBAAmB,EAAEC,8BAA8B,QAAQ,wBAAwB;AAE5F,SACIC,eAAe,EACfC,mBAAmB,EACnBC,oBAAoB,EACpBC,cAAc,QACX,qBAAqB;AAC5B,SAASC,eAAe,QAAQ,qBAAqB;AACrD,SAASC,gCAAgC,QAAQ,2BAA2B;AAE5E,MAAMC,gBAA4B,GAAG,EAAE;AAEvC,MAAMC,aAAqC,GAAGA,CAAC;EAC3CC,KAAK;EACLC,gBAAgB,GAAG,IAAI;EACvBC,QAAQ,GAAGN,eAAe,CAACO;AAC/B,CAAC,KAAK;EACF,MAAMC,SAAS,GAAGJ,KAAK,IAAIF,gBAAgB;EAC3C,MAAMO,KAAK,GAAGb,eAAe,CAACY,SAAS,CAAC;EAExC,MAAME,eAAe,GAAGlB,WAAW,CAC9BmB,IAAc,IAAK;IAChBZ,cAAc,CAACS,SAAS,EAAEG,IAAI,CAAC;EACnC,CAAC,EACD,CAACH,SAAS,CACd,CAAC;EAED,MAAMI,YAAY,GAAGJ,SAAS,CAACK,KAAK,CAAC,CAAC,EAAEZ,gCAAgC,CAAC;EAEzE,oBACIV,KAAA,CAAAuB,aAAA,CAACpB,mBAAmB,qBAChBH,KAAA,CAAAuB,aAAA,CAACnB,8BAA8B;IAC3BoB,MAAM,EAAEN,KAAM;IACdO,UAAU,EAAER,SAAS,CAACS,MAAO;IAC7BC,SAAS,EAAEZ;EAAS,GAEnBM,YAAY,CAACO,GAAG,CAAC,CAACR,IAAI,EAAES,KAAK,kBAC1B7B,KAAA,CAAAuB,aAAA,CAACrB,iBAAiB;IACd4B,GAAG,EAAExB,mBAAmB,CAACc,IAAI,EAAES,KAAK,CAAE;IACtCE,QAAQ,EAAEX,IAAK;IACfY,OAAO,EAAEb,eAAgB;IACzBD,KAAK,EAAEX,oBAAoB,CAAC;MAAEU,SAAS;MAAEY,KAAK;MAAEd;IAAS,CAAC,CAAE;IAC5DD,gBAAgB,EAAEA,gBAAiB;IACnCmB,oBAAoB,EAChBhB,SAAS,CAACS,MAAM,GAAGhB,gCAAgC,IAAImB,KAAK,KAAK,CAAC,GAC5DZ,SAAS,CAACS,MAAM,GAChBQ;EACT,CACJ,CACJ,CAC2B,CACf,CAAC;AAE9B,CAAC;AAEDtB,aAAa,CAACuB,WAAW,GAAG,eAAe;AAE3C,eAAevB,aAAa","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"GalleryViewer.types.js","names":[],"sources":["../../../../src/components/gallery-viewer/GalleryViewer.types.ts"],"sourcesContent":["import type { FileItem } from '@chayns-components/core';\nimport type { GalleryViewMode } from '../../types/gallery';\n\n/**\n * Props for the prop-driven read-only gallery viewer.\n */\nexport interface GalleryViewerProps {\n /**\n * Provides the already known media items that should be rendered without local upload state.\n * @description\n * The viewer renders these files directly from props and does not mirror them into local component state.\n * @example\n * <GalleryViewer files={files} />\n * @optional\n */\n files?: FileItem[];\n /**\n * Defines how the media tiles are arranged in read-only mode.\n * @description\n * Use this prop to switch between the supported viewer layouts for known media.\n * @default GalleryViewMode.GRID\n * @example\n * <GalleryViewer files={files} viewMode={GalleryViewMode.SQUARE} />\n * @optional\n */\n viewMode?: GalleryViewMode;\n}\n"],"mappings":"","ignoreList":[]}
1
+ {"version":3,"file":"GalleryViewer.types.js","names":[],"sources":["../../../../src/components/gallery-viewer/GalleryViewer.types.ts"],"sourcesContent":["import type { FileItem } from '@chayns-components/core';\nimport type { GalleryViewMode } from '../../types/gallery';\n\n/**\n * Props for the prop-driven read-only gallery viewer.\n */\nexport interface GalleryViewerProps {\n /**\n * Provides the already known media items that should be rendered without local upload state.\n * @description\n * The viewer renders these files directly from props and does not mirror them into local component state.\n * @example\n * <GalleryViewer files={files} />\n * @optional\n */\n files?: FileItem[];\n /**\n * Controls whether the viewer may load the final media assets immediately.\n * @description\n * When set to `true`, the viewer renders and loads the actual images right away.\n * When set to `false`, the viewer keeps showing previews first and defers the final image load until this flag becomes `true`.\n * @default true\n * @example\n * <GalleryViewer files={files} shouldLoadImages={false} />\n * @optional\n */\n shouldLoadImages?: boolean;\n /**\n * Defines how the media tiles are arranged in read-only mode.\n * @description\n * Use this prop to switch between the supported viewer layouts for known media.\n * @default GalleryViewMode.GRID\n * @example\n * <GalleryViewer files={files} viewMode={GalleryViewMode.SQUARE} />\n * @optional\n */\n viewMode?: GalleryViewMode;\n}\n"],"mappings":"","ignoreList":[]}
@@ -1,18 +1,20 @@
1
- import React from 'react';
1
+ import React, { memo } from 'react';
2
2
  import MediaContent from '../../media-content/MediaContent';
3
3
  import { StyledGalleryViewerItem, StyledGalleryViewerMoreItemsIndicator } from './GalleryViewerItem.styles';
4
4
  const GalleryViewerItem = ({
5
5
  fileItem,
6
+ shouldLoadImages = true,
6
7
  ratio = 1,
7
8
  remainingItemsLength,
8
9
  onClick
9
10
  }) => /*#__PURE__*/React.createElement(StyledGalleryViewerItem, null, /*#__PURE__*/React.createElement(MediaContent, {
10
11
  file: fileItem.file,
11
12
  onClick: () => onClick(fileItem),
12
- ratio: ratio
13
+ ratio: ratio,
14
+ shouldLoadImages: shouldLoadImages
13
15
  }), remainingItemsLength && /*#__PURE__*/React.createElement(StyledGalleryViewerMoreItemsIndicator, {
14
16
  onClick: () => onClick(fileItem)
15
17
  }, /*#__PURE__*/React.createElement("p", null, `+ ${remainingItemsLength - 3}`)));
16
18
  GalleryViewerItem.displayName = 'GalleryViewerItem';
17
- export default GalleryViewerItem;
19
+ export default /*#__PURE__*/memo(GalleryViewerItem);
18
20
  //# sourceMappingURL=GalleryViewerItem.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"GalleryViewerItem.js","names":["React","MediaContent","StyledGalleryViewerItem","StyledGalleryViewerMoreItemsIndicator","GalleryViewerItem","fileItem","ratio","remainingItemsLength","onClick","createElement","file","displayName"],"sources":["../../../../../src/components/gallery-viewer/gallery-viewer-item/GalleryViewerItem.tsx"],"sourcesContent":["import React, { FC } from 'react';\nimport MediaContent from '../../media-content/MediaContent';\nimport {\n StyledGalleryViewerItem,\n StyledGalleryViewerMoreItemsIndicator,\n} from './GalleryViewerItem.styles';\nimport type { GalleryViewerItemProps } from './GalleryViewerItem.types';\n\nconst GalleryViewerItem: FC<GalleryViewerItemProps> = ({\n fileItem,\n ratio = 1,\n remainingItemsLength,\n onClick,\n}) => (\n <StyledGalleryViewerItem>\n <MediaContent file={fileItem.file} onClick={() => onClick(fileItem)} ratio={ratio} />\n {remainingItemsLength && (\n <StyledGalleryViewerMoreItemsIndicator onClick={() => onClick(fileItem)}>\n <p>{`+ ${remainingItemsLength - 3}`}</p>\n </StyledGalleryViewerMoreItemsIndicator>\n )}\n </StyledGalleryViewerItem>\n);\n\nGalleryViewerItem.displayName = 'GalleryViewerItem';\n\nexport default GalleryViewerItem;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAc,OAAO;AACjC,OAAOC,YAAY,MAAM,kCAAkC;AAC3D,SACIC,uBAAuB,EACvBC,qCAAqC,QAClC,4BAA4B;AAGnC,MAAMC,iBAA6C,GAAGA,CAAC;EACnDC,QAAQ;EACRC,KAAK,GAAG,CAAC;EACTC,oBAAoB;EACpBC;AACJ,CAAC,kBACGR,KAAA,CAAAS,aAAA,CAACP,uBAAuB,qBACpBF,KAAA,CAAAS,aAAA,CAACR,YAAY;EAACS,IAAI,EAAEL,QAAQ,CAACK,IAAK;EAACF,OAAO,EAAEA,CAAA,KAAMA,OAAO,CAACH,QAAQ,CAAE;EAACC,KAAK,EAAEA;AAAM,CAAE,CAAC,EACpFC,oBAAoB,iBACjBP,KAAA,CAAAS,aAAA,CAACN,qCAAqC;EAACK,OAAO,EAAEA,CAAA,KAAMA,OAAO,CAACH,QAAQ;AAAE,gBACpEL,KAAA,CAAAS,aAAA,YAAI,KAAKF,oBAAoB,GAAG,CAAC,EAAM,CACJ,CAEtB,CAC5B;AAEDH,iBAAiB,CAACO,WAAW,GAAG,mBAAmB;AAEnD,eAAeP,iBAAiB","ignoreList":[]}
1
+ {"version":3,"file":"GalleryViewerItem.js","names":["React","memo","MediaContent","StyledGalleryViewerItem","StyledGalleryViewerMoreItemsIndicator","GalleryViewerItem","fileItem","shouldLoadImages","ratio","remainingItemsLength","onClick","createElement","file","displayName"],"sources":["../../../../../src/components/gallery-viewer/gallery-viewer-item/GalleryViewerItem.tsx"],"sourcesContent":["import React, { FC, memo } from 'react';\nimport MediaContent from '../../media-content/MediaContent';\nimport {\n StyledGalleryViewerItem,\n StyledGalleryViewerMoreItemsIndicator,\n} from './GalleryViewerItem.styles';\nimport type { GalleryViewerItemProps } from './GalleryViewerItem.types';\n\nconst GalleryViewerItem: FC<GalleryViewerItemProps> = ({\n fileItem,\n shouldLoadImages = true,\n ratio = 1,\n remainingItemsLength,\n onClick,\n}) => (\n <StyledGalleryViewerItem>\n <MediaContent\n file={fileItem.file}\n onClick={() => onClick(fileItem)}\n ratio={ratio}\n shouldLoadImages={shouldLoadImages}\n />\n {remainingItemsLength && (\n <StyledGalleryViewerMoreItemsIndicator onClick={() => onClick(fileItem)}>\n <p>{`+ ${remainingItemsLength - 3}`}</p>\n </StyledGalleryViewerMoreItemsIndicator>\n )}\n </StyledGalleryViewerItem>\n);\n\nGalleryViewerItem.displayName = 'GalleryViewerItem';\n\nexport default memo(GalleryViewerItem);\n"],"mappings":"AAAA,OAAOA,KAAK,IAAQC,IAAI,QAAQ,OAAO;AACvC,OAAOC,YAAY,MAAM,kCAAkC;AAC3D,SACIC,uBAAuB,EACvBC,qCAAqC,QAClC,4BAA4B;AAGnC,MAAMC,iBAA6C,GAAGA,CAAC;EACnDC,QAAQ;EACRC,gBAAgB,GAAG,IAAI;EACvBC,KAAK,GAAG,CAAC;EACTC,oBAAoB;EACpBC;AACJ,CAAC,kBACGV,KAAA,CAAAW,aAAA,CAACR,uBAAuB,qBACpBH,KAAA,CAAAW,aAAA,CAACT,YAAY;EACTU,IAAI,EAAEN,QAAQ,CAACM,IAAK;EACpBF,OAAO,EAAEA,CAAA,KAAMA,OAAO,CAACJ,QAAQ,CAAE;EACjCE,KAAK,EAAEA,KAAM;EACbD,gBAAgB,EAAEA;AAAiB,CACtC,CAAC,EACDE,oBAAoB,iBACjBT,KAAA,CAAAW,aAAA,CAACP,qCAAqC;EAACM,OAAO,EAAEA,CAAA,KAAMA,OAAO,CAACJ,QAAQ;AAAE,gBACpEN,KAAA,CAAAW,aAAA,YAAI,KAAKF,oBAAoB,GAAG,CAAC,EAAM,CACJ,CAEtB,CAC5B;AAEDJ,iBAAiB,CAACQ,WAAW,GAAG,mBAAmB;AAEnD,4BAAeZ,IAAI,CAACI,iBAAiB,CAAC","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"GalleryViewerItem.types.js","names":[],"sources":["../../../../../src/components/gallery-viewer/gallery-viewer-item/GalleryViewerItem.types.ts"],"sourcesContent":["import type { FileItem } from '@chayns-components/core';\n\n/**\n * Props for a dedicated read-only gallery tile.\n */\nexport interface GalleryViewerItemProps {\n /**\n * Provides the uploaded media that should be rendered.\n * @description\n * The viewer item renders only already known media and never deals with upload-specific transient state.\n * @example\n * <GalleryViewerItem fileItem={file} onClick={handleOpen} />\n */\n fileItem: FileItem;\n /**\n * Defines the aspect ratio that should be reserved for the tile.\n * @description\n * Use this prop to reserve a deterministic tile height for stable read-only rendering.\n * @default 1\n * @example\n * <GalleryViewerItem fileItem={file} onClick={handleOpen} ratio={1.5} />\n * @optional\n */\n ratio?: number;\n /**\n * Provides the total item count when the last visible tile should show a remaining-items overlay.\n * @description\n * When this prop is set on the last visible viewer tile, the tile displays the `+n` overlay for hidden items.\n * @example\n * <GalleryViewerItem fileItem={file} onClick={handleOpen} remainingItemsLength={5} />\n * @optional\n */\n remainingItemsLength?: number;\n /**\n * Is called when the tile is selected.\n * @description\n * The viewer uses this callback to open the selected file inside the slideshow flow.\n * @example\n * <GalleryViewerItem fileItem={file} onClick={handleOpen} />\n */\n onClick: (file: FileItem) => void;\n}\n"],"mappings":"","ignoreList":[]}
1
+ {"version":3,"file":"GalleryViewerItem.types.js","names":[],"sources":["../../../../../src/components/gallery-viewer/gallery-viewer-item/GalleryViewerItem.types.ts"],"sourcesContent":["import type { FileItem } from '@chayns-components/core';\n\n/**\n * Props for a dedicated read-only gallery tile.\n */\nexport interface GalleryViewerItemProps {\n /**\n * Provides the uploaded media that should be rendered.\n * @description\n * The viewer item renders only already known media and never deals with upload-specific transient state.\n * @example\n * <GalleryViewerItem fileItem={file} onClick={handleOpen} />\n */\n fileItem: FileItem;\n /**\n * Controls whether the item may load the final media source immediately.\n * @description\n * The item forwards this flag to the shared media renderer so preview-first rendering can be controlled by the parent gallery.\n * @default true\n * @optional\n */\n shouldLoadImages?: boolean;\n /**\n * Defines the aspect ratio that should be reserved for the tile.\n * @description\n * Use this prop to reserve a deterministic tile height for stable read-only rendering.\n * @default 1\n * @example\n * <GalleryViewerItem fileItem={file} onClick={handleOpen} ratio={1.5} />\n * @optional\n */\n ratio?: number;\n /**\n * Provides the total item count when the last visible tile should show a remaining-items overlay.\n * @description\n * When this prop is set on the last visible viewer tile, the tile displays the `+n` overlay for hidden items.\n * @example\n * <GalleryViewerItem fileItem={file} onClick={handleOpen} remainingItemsLength={5} />\n * @optional\n */\n remainingItemsLength?: number;\n /**\n * Is called when the tile is selected.\n * @description\n * The viewer uses this callback to open the selected file inside the slideshow flow.\n * @example\n * <GalleryViewerItem fileItem={file} onClick={handleOpen} />\n */\n onClick: (file: FileItem) => void;\n}\n"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,6 @@
1
+ export const MEDIA_CONTENT_IMAGE_FADE_DURATION_MS = 200;
2
+ export const MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DELAY_MS = 100;
3
+ export const MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DURATION_MS = 200;
4
+ export const MEDIA_CONTENT_PREVIEW_BLUR = 'blur(16px)';
5
+ export const MEDIA_CONTENT_PREVIEW_SCALE = 1.05;
6
+ //# sourceMappingURL=MediaContent.constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaContent.constants.js","names":["MEDIA_CONTENT_IMAGE_FADE_DURATION_MS","MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DELAY_MS","MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DURATION_MS","MEDIA_CONTENT_PREVIEW_BLUR","MEDIA_CONTENT_PREVIEW_SCALE"],"sources":["../../../../src/components/media-content/MediaContent.constants.ts"],"sourcesContent":["export const MEDIA_CONTENT_IMAGE_FADE_DURATION_MS = 200;\nexport const MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DELAY_MS = 100;\nexport const MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DURATION_MS = 200;\nexport const MEDIA_CONTENT_PREVIEW_BLUR = 'blur(16px)';\nexport const MEDIA_CONTENT_PREVIEW_SCALE = 1.05;\n"],"mappings":"AAAA,OAAO,MAAMA,oCAAoC,GAAG,GAAG;AACvD,OAAO,MAAMC,wCAAwC,GAAG,GAAG;AAC3D,OAAO,MAAMC,2CAA2C,GAAG,GAAG;AAC9D,OAAO,MAAMC,0BAA0B,GAAG,YAAY;AACtD,OAAO,MAAMC,2BAA2B,GAAG,IAAI","ignoreList":[]}
@@ -1,29 +1,102 @@
1
1
  import { Icon } from '@chayns-components/core';
2
- import React from 'react';
3
- import { StyledMediaContentImage, StyledMediaContentImageWrapper, StyledMediaContentPlayIcon, StyledMediaContentVideo, StyledMediaContentVideoWrapper } from './MediaContent.styles';
2
+ import React, { memo, useLayoutEffect, useMemo, useRef, useState } from 'react';
3
+ import { StyledMediaContentImage, StyledMediaContentImageWrapper, StyledMediaContentPlayIcon, StyledMediaContentPreviewImage, StyledMediaContentVideo, StyledMediaContentVideoWrapper } from './MediaContent.styles';
4
+ import { getMediaPreviewUrl, getMediaSourceUrl, getResponsiveImageServiceUrl, isVideoFile } from './MediaContent.utils';
5
+ import { MEDIA_CONTENT_IMAGE_FADE_DURATION_MS, MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DELAY_MS, MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DURATION_MS, MEDIA_CONTENT_PREVIEW_BLUR, MEDIA_CONTENT_PREVIEW_SCALE } from './MediaContent.constants';
6
+ import useMediaContentSize from './useMediaContentSize';
4
7
  const MediaContent = ({
5
8
  file,
9
+ previewUrl,
6
10
  ratio,
7
11
  onClick,
12
+ shouldLoadImages = true,
8
13
  playIconSize = 50
9
- }) => 'thumbnailUrl' in file ? /*#__PURE__*/React.createElement(StyledMediaContentVideoWrapper, {
10
- onClick: onClick,
11
- $ratio: ratio
12
- }, /*#__PURE__*/React.createElement(StyledMediaContentPlayIcon, null, /*#__PURE__*/React.createElement(Icon, {
13
- size: playIconSize,
14
- icons: ['fa fa-play']
15
- })), /*#__PURE__*/React.createElement(StyledMediaContentVideo, {
16
- poster: file.thumbnailUrl
17
- }, /*#__PURE__*/React.createElement("source", {
18
- src: file.url,
19
- type: "video/mp4"
20
- }))) : /*#__PURE__*/React.createElement(StyledMediaContentImageWrapper, {
21
- onClick: onClick,
22
- $ratio: ratio
23
- }, /*#__PURE__*/React.createElement(StyledMediaContentImage, {
24
- draggable: false,
25
- src: file.url
26
- }));
14
+ }) => {
15
+ const isVideo = isVideoFile(file);
16
+ const sourceKey = getMediaSourceUrl(file);
17
+ const previewSourceUrl = getMediaPreviewUrl(file, previewUrl);
18
+ const [hasLoadedFinalMedia, setHasLoadedFinalMedia] = useState(false);
19
+ const imageRef = useRef(null);
20
+ const videoRef = useRef(null);
21
+ const [containerElement, setContainerElement] = useState(null);
22
+ const renderSize = useMediaContentSize(containerElement);
23
+ const devicePixelRatio = typeof window !== 'undefined' && Number.isFinite(window.devicePixelRatio) && window.devicePixelRatio > 0 ? window.devicePixelRatio : 1;
24
+ const finalSourceUrl = useMemo(() => isVideo ? sourceKey : getResponsiveImageServiceUrl(sourceKey, renderSize, devicePixelRatio), [devicePixelRatio, isVideo, renderSize, sourceKey]);
25
+ const displayPreviewUrl = useMemo(() => previewSourceUrl ? getResponsiveImageServiceUrl(previewSourceUrl, renderSize, devicePixelRatio) : undefined, [devicePixelRatio, previewSourceUrl, renderSize]);
26
+ useLayoutEffect(() => {
27
+ setHasLoadedFinalMedia(false);
28
+ }, [sourceKey]);
29
+ useLayoutEffect(() => {
30
+ if (!shouldLoadImages) {
31
+ return;
32
+ }
33
+ if (!isVideo && imageRef.current?.complete && imageRef.current.naturalWidth > 0) {
34
+ setHasLoadedFinalMedia(true);
35
+ }
36
+ if (isVideo && videoRef.current?.readyState && videoRef.current.readyState >= 2) {
37
+ setHasLoadedFinalMedia(true);
38
+ }
39
+ }, [finalSourceUrl, isVideo, shouldLoadImages]);
40
+ const shouldRenderFinalImage = shouldLoadImages && Boolean(finalSourceUrl);
41
+ const shouldShowPreview = Boolean(displayPreviewUrl);
42
+ if (isVideo) {
43
+ return /*#__PURE__*/React.createElement(StyledMediaContentVideoWrapper, {
44
+ ref: setContainerElement,
45
+ onClick: onClick,
46
+ $ratio: ratio
47
+ }, displayPreviewUrl && /*#__PURE__*/React.createElement(StyledMediaContentPreviewImage, {
48
+ draggable: false,
49
+ src: displayPreviewUrl,
50
+ alt: "",
51
+ "aria-hidden": "true",
52
+ style: {
53
+ opacity: shouldLoadImages && hasLoadedFinalMedia ? 0 : 1
54
+ }
55
+ }), /*#__PURE__*/React.createElement(StyledMediaContentPlayIcon, null, /*#__PURE__*/React.createElement(Icon, {
56
+ size: playIconSize,
57
+ icons: ['fa fa-play']
58
+ })), shouldRenderFinalImage && /*#__PURE__*/React.createElement(StyledMediaContentVideo, {
59
+ ref: videoRef,
60
+ poster: displayPreviewUrl,
61
+ preload: "metadata",
62
+ onLoadedData: () => setHasLoadedFinalMedia(true),
63
+ style: {
64
+ filter: displayPreviewUrl && !hasLoadedFinalMedia ? MEDIA_CONTENT_PREVIEW_BLUR : 'none',
65
+ transform: displayPreviewUrl && !hasLoadedFinalMedia ? `scale(${MEDIA_CONTENT_PREVIEW_SCALE})` : 'none',
66
+ opacity: hasLoadedFinalMedia || !displayPreviewUrl ? 1 : 0,
67
+ transition: `opacity ${MEDIA_CONTENT_IMAGE_FADE_DURATION_MS}ms ease, filter ${MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DURATION_MS}ms ease ${MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DELAY_MS}ms, transform ${MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DURATION_MS}ms ease ${MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DELAY_MS}ms`
68
+ }
69
+ }, /*#__PURE__*/React.createElement("source", {
70
+ src: finalSourceUrl,
71
+ type: "video/mp4"
72
+ })));
73
+ }
74
+ return /*#__PURE__*/React.createElement(StyledMediaContentImageWrapper, {
75
+ ref: setContainerElement,
76
+ onClick: onClick,
77
+ $ratio: ratio
78
+ }, shouldShowPreview && /*#__PURE__*/React.createElement(StyledMediaContentPreviewImage, {
79
+ draggable: false,
80
+ src: displayPreviewUrl,
81
+ alt: "",
82
+ "aria-hidden": "true",
83
+ style: {
84
+ opacity: shouldLoadImages && hasLoadedFinalMedia ? 0 : 1
85
+ }
86
+ }), shouldRenderFinalImage && /*#__PURE__*/React.createElement(StyledMediaContentImage, {
87
+ ref: imageRef,
88
+ draggable: false,
89
+ src: finalSourceUrl,
90
+ alt: "",
91
+ onLoad: () => setHasLoadedFinalMedia(true),
92
+ style: {
93
+ filter: displayPreviewUrl && !hasLoadedFinalMedia ? MEDIA_CONTENT_PREVIEW_BLUR : 'none',
94
+ transform: displayPreviewUrl && !hasLoadedFinalMedia ? `scale(${MEDIA_CONTENT_PREVIEW_SCALE})` : 'none',
95
+ opacity: hasLoadedFinalMedia || !displayPreviewUrl ? 1 : 0,
96
+ transition: `opacity ${MEDIA_CONTENT_IMAGE_FADE_DURATION_MS}ms ease, filter ${MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DURATION_MS}ms ease ${MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DELAY_MS}ms, transform ${MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DURATION_MS}ms ease ${MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DELAY_MS}ms`
97
+ }
98
+ }));
99
+ };
27
100
  MediaContent.displayName = 'MediaContent';
28
- export default MediaContent;
101
+ export default /*#__PURE__*/memo(MediaContent);
29
102
  //# sourceMappingURL=MediaContent.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MediaContent.js","names":["Icon","React","StyledMediaContentImage","StyledMediaContentImageWrapper","StyledMediaContentPlayIcon","StyledMediaContentVideo","StyledMediaContentVideoWrapper","MediaContent","file","ratio","onClick","playIconSize","createElement","$ratio","size","icons","poster","thumbnailUrl","src","url","type","draggable","displayName"],"sources":["../../../../src/components/media-content/MediaContent.tsx"],"sourcesContent":["import { Icon } from '@chayns-components/core';\nimport React, { FC } from 'react';\nimport {\n StyledMediaContentImage,\n StyledMediaContentImageWrapper,\n StyledMediaContentPlayIcon,\n StyledMediaContentVideo,\n StyledMediaContentVideoWrapper,\n} from './MediaContent.styles';\nimport type { MediaContentProps } from './MediaContent.types';\n\nconst MediaContent: FC<MediaContentProps> = ({ file, ratio, onClick, playIconSize = 50 }) =>\n 'thumbnailUrl' in file ? (\n <StyledMediaContentVideoWrapper onClick={onClick} $ratio={ratio}>\n <StyledMediaContentPlayIcon>\n <Icon size={playIconSize} icons={['fa fa-play']} />\n </StyledMediaContentPlayIcon>\n <StyledMediaContentVideo poster={file.thumbnailUrl}>\n <source src={file.url} type=\"video/mp4\" />\n </StyledMediaContentVideo>\n </StyledMediaContentVideoWrapper>\n ) : (\n <StyledMediaContentImageWrapper onClick={onClick} $ratio={ratio}>\n <StyledMediaContentImage draggable={false} src={file.url} />\n </StyledMediaContentImageWrapper>\n );\n\nMediaContent.displayName = 'MediaContent';\n\nexport default MediaContent;\n"],"mappings":"AAAA,SAASA,IAAI,QAAQ,yBAAyB;AAC9C,OAAOC,KAAK,MAAc,OAAO;AACjC,SACIC,uBAAuB,EACvBC,8BAA8B,EAC9BC,0BAA0B,EAC1BC,uBAAuB,EACvBC,8BAA8B,QAC3B,uBAAuB;AAG9B,MAAMC,YAAmC,GAAGA,CAAC;EAAEC,IAAI;EAAEC,KAAK;EAAEC,OAAO;EAAEC,YAAY,GAAG;AAAG,CAAC,KACpF,cAAc,IAAIH,IAAI,gBAClBP,KAAA,CAAAW,aAAA,CAACN,8BAA8B;EAACI,OAAO,EAAEA,OAAQ;EAACG,MAAM,EAAEJ;AAAM,gBAC5DR,KAAA,CAAAW,aAAA,CAACR,0BAA0B,qBACvBH,KAAA,CAAAW,aAAA,CAACZ,IAAI;EAACc,IAAI,EAAEH,YAAa;EAACI,KAAK,EAAE,CAAC,YAAY;AAAE,CAAE,CAC1B,CAAC,eAC7Bd,KAAA,CAAAW,aAAA,CAACP,uBAAuB;EAACW,MAAM,EAAER,IAAI,CAACS;AAAa,gBAC/ChB,KAAA,CAAAW,aAAA;EAAQM,GAAG,EAAEV,IAAI,CAACW,GAAI;EAACC,IAAI,EAAC;AAAW,CAAE,CACpB,CACG,CAAC,gBAEjCnB,KAAA,CAAAW,aAAA,CAACT,8BAA8B;EAACO,OAAO,EAAEA,OAAQ;EAACG,MAAM,EAAEJ;AAAM,gBAC5DR,KAAA,CAAAW,aAAA,CAACV,uBAAuB;EAACmB,SAAS,EAAE,KAAM;EAACH,GAAG,EAAEV,IAAI,CAACW;AAAI,CAAE,CAC/B,CACnC;AAELZ,YAAY,CAACe,WAAW,GAAG,cAAc;AAEzC,eAAef,YAAY","ignoreList":[]}
1
+ {"version":3,"file":"MediaContent.js","names":["Icon","React","memo","useLayoutEffect","useMemo","useRef","useState","StyledMediaContentImage","StyledMediaContentImageWrapper","StyledMediaContentPlayIcon","StyledMediaContentPreviewImage","StyledMediaContentVideo","StyledMediaContentVideoWrapper","getMediaPreviewUrl","getMediaSourceUrl","getResponsiveImageServiceUrl","isVideoFile","MEDIA_CONTENT_IMAGE_FADE_DURATION_MS","MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DELAY_MS","MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DURATION_MS","MEDIA_CONTENT_PREVIEW_BLUR","MEDIA_CONTENT_PREVIEW_SCALE","useMediaContentSize","MediaContent","file","previewUrl","ratio","onClick","shouldLoadImages","playIconSize","isVideo","sourceKey","previewSourceUrl","hasLoadedFinalMedia","setHasLoadedFinalMedia","imageRef","videoRef","containerElement","setContainerElement","renderSize","devicePixelRatio","window","Number","isFinite","finalSourceUrl","displayPreviewUrl","undefined","current","complete","naturalWidth","readyState","shouldRenderFinalImage","Boolean","shouldShowPreview","createElement","ref","$ratio","draggable","src","alt","style","opacity","size","icons","poster","preload","onLoadedData","filter","transform","transition","type","onLoad","displayName"],"sources":["../../../../src/components/media-content/MediaContent.tsx"],"sourcesContent":["import { Icon } from '@chayns-components/core';\nimport React, { FC, memo, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport {\n StyledMediaContentImage,\n StyledMediaContentImageWrapper,\n StyledMediaContentPlayIcon,\n StyledMediaContentPreviewImage,\n StyledMediaContentVideo,\n StyledMediaContentVideoWrapper,\n} from './MediaContent.styles';\nimport type { MediaContentProps } from './MediaContent.types';\nimport {\n getMediaPreviewUrl,\n getMediaSourceUrl,\n getResponsiveImageServiceUrl,\n isVideoFile,\n} from './MediaContent.utils';\nimport {\n MEDIA_CONTENT_IMAGE_FADE_DURATION_MS,\n MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DELAY_MS,\n MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DURATION_MS,\n MEDIA_CONTENT_PREVIEW_BLUR,\n MEDIA_CONTENT_PREVIEW_SCALE,\n} from './MediaContent.constants';\nimport useMediaContentSize from './useMediaContentSize';\n\nconst MediaContent: FC<MediaContentProps> = ({\n file,\n previewUrl,\n ratio,\n onClick,\n shouldLoadImages = true,\n playIconSize = 50,\n}) => {\n const isVideo = isVideoFile(file);\n const sourceKey = getMediaSourceUrl(file);\n const previewSourceUrl = getMediaPreviewUrl(file, previewUrl);\n const [hasLoadedFinalMedia, setHasLoadedFinalMedia] = useState(false);\n const imageRef = useRef<HTMLImageElement>(null);\n const videoRef = useRef<HTMLVideoElement>(null);\n const [containerElement, setContainerElement] = useState<HTMLDivElement | null>(null);\n const renderSize = useMediaContentSize(containerElement);\n const devicePixelRatio =\n typeof window !== 'undefined' &&\n Number.isFinite(window.devicePixelRatio) &&\n window.devicePixelRatio > 0\n ? window.devicePixelRatio\n : 1;\n\n const finalSourceUrl = useMemo(\n () =>\n isVideo\n ? sourceKey\n : getResponsiveImageServiceUrl(sourceKey, renderSize, devicePixelRatio),\n [devicePixelRatio, isVideo, renderSize, sourceKey],\n );\n const displayPreviewUrl = useMemo(\n () =>\n previewSourceUrl\n ? getResponsiveImageServiceUrl(previewSourceUrl, renderSize, devicePixelRatio)\n : undefined,\n [devicePixelRatio, previewSourceUrl, renderSize],\n );\n\n useLayoutEffect(() => {\n setHasLoadedFinalMedia(false);\n }, [sourceKey]);\n\n useLayoutEffect(() => {\n if (!shouldLoadImages) {\n return;\n }\n\n if (!isVideo && imageRef.current?.complete && imageRef.current.naturalWidth > 0) {\n setHasLoadedFinalMedia(true);\n }\n\n if (isVideo && videoRef.current?.readyState && videoRef.current.readyState >= 2) {\n setHasLoadedFinalMedia(true);\n }\n }, [finalSourceUrl, isVideo, shouldLoadImages]);\n\n const shouldRenderFinalImage = shouldLoadImages && Boolean(finalSourceUrl);\n const shouldShowPreview = Boolean(displayPreviewUrl);\n\n if (isVideo) {\n return (\n <StyledMediaContentVideoWrapper\n ref={setContainerElement}\n onClick={onClick}\n $ratio={ratio}\n >\n {displayPreviewUrl && (\n <StyledMediaContentPreviewImage\n draggable={false}\n src={displayPreviewUrl}\n alt=\"\"\n aria-hidden=\"true\"\n style={{\n opacity: shouldLoadImages && hasLoadedFinalMedia ? 0 : 1,\n }}\n />\n )}\n <StyledMediaContentPlayIcon>\n <Icon size={playIconSize} icons={['fa fa-play']} />\n </StyledMediaContentPlayIcon>\n {shouldRenderFinalImage && (\n <StyledMediaContentVideo\n ref={videoRef}\n poster={displayPreviewUrl}\n preload=\"metadata\"\n onLoadedData={() => setHasLoadedFinalMedia(true)}\n style={{\n filter:\n displayPreviewUrl && !hasLoadedFinalMedia\n ? MEDIA_CONTENT_PREVIEW_BLUR\n : 'none',\n transform:\n displayPreviewUrl && !hasLoadedFinalMedia\n ? `scale(${MEDIA_CONTENT_PREVIEW_SCALE})`\n : 'none',\n opacity: hasLoadedFinalMedia || !displayPreviewUrl ? 1 : 0,\n transition: `opacity ${MEDIA_CONTENT_IMAGE_FADE_DURATION_MS}ms ease, filter ${MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DURATION_MS}ms ease ${MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DELAY_MS}ms, transform ${MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DURATION_MS}ms ease ${MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DELAY_MS}ms`,\n }}\n >\n <source src={finalSourceUrl} type=\"video/mp4\" />\n </StyledMediaContentVideo>\n )}\n </StyledMediaContentVideoWrapper>\n );\n }\n\n return (\n <StyledMediaContentImageWrapper ref={setContainerElement} onClick={onClick} $ratio={ratio}>\n {shouldShowPreview && (\n <StyledMediaContentPreviewImage\n draggable={false}\n src={displayPreviewUrl}\n alt=\"\"\n aria-hidden=\"true\"\n style={{\n opacity: shouldLoadImages && hasLoadedFinalMedia ? 0 : 1,\n }}\n />\n )}\n {shouldRenderFinalImage && (\n <StyledMediaContentImage\n ref={imageRef}\n draggable={false}\n src={finalSourceUrl}\n alt=\"\"\n onLoad={() => setHasLoadedFinalMedia(true)}\n style={{\n filter:\n displayPreviewUrl && !hasLoadedFinalMedia\n ? MEDIA_CONTENT_PREVIEW_BLUR\n : 'none',\n transform:\n displayPreviewUrl && !hasLoadedFinalMedia\n ? `scale(${MEDIA_CONTENT_PREVIEW_SCALE})`\n : 'none',\n opacity: hasLoadedFinalMedia || !displayPreviewUrl ? 1 : 0,\n transition: `opacity ${MEDIA_CONTENT_IMAGE_FADE_DURATION_MS}ms ease, filter ${MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DURATION_MS}ms ease ${MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DELAY_MS}ms, transform ${MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DURATION_MS}ms ease ${MEDIA_CONTENT_IMAGE_BLUR_REMOVE_DELAY_MS}ms`,\n }}\n />\n )}\n </StyledMediaContentImageWrapper>\n );\n};\n\nMediaContent.displayName = 'MediaContent';\n\nexport default memo(MediaContent);\n"],"mappings":"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","ignoreList":[]}
@@ -1,6 +1,9 @@
1
1
  import styled from 'styled-components';
2
+ import { MEDIA_CONTENT_IMAGE_FADE_DURATION_MS, MEDIA_CONTENT_PREVIEW_BLUR, MEDIA_CONTENT_PREVIEW_SCALE } from './MediaContent.constants';
2
3
  export const StyledMediaContentVideoWrapper = styled.div`
3
4
  display: flex;
5
+ position: relative;
6
+ overflow: hidden;
4
7
  width: 100%;
5
8
  height: 100%;
6
9
  aspect-ratio: ${({
@@ -9,13 +12,23 @@ export const StyledMediaContentVideoWrapper = styled.div`
9
12
  `;
10
13
  export const StyledMediaContentImageWrapper = styled.div`
11
14
  display: flex;
15
+ position: relative;
16
+ overflow: hidden;
12
17
  width: 100%;
13
18
  height: 100%;
14
19
  aspect-ratio: ${({
15
20
  $ratio
16
21
  }) => $ratio};
17
22
  `;
18
- export const StyledMediaContentImage = styled.img`
23
+ const StyledMediaContentLayer = styled.img`
24
+ position: absolute;
25
+ inset: 0;
26
+ width: 100%;
27
+ height: 100%;
28
+ object-fit: cover;
29
+ pointer-events: none;
30
+ `;
31
+ export const StyledMediaContentPreviewImage = styled(StyledMediaContentLayer)`
19
32
  background-color: ${({
20
33
  theme
21
34
  }) => theme['101']};
@@ -24,9 +37,22 @@ export const StyledMediaContentImage = styled.img`
24
37
  theme
25
38
  }) => theme['009-rgb']}, 0.08) inset;
26
39
  z-index: 1;
27
- width: 100%;
28
- height: 100%;
29
- object-fit: cover;
40
+ filter: ${MEDIA_CONTENT_PREVIEW_BLUR};
41
+ transform: scale(${MEDIA_CONTENT_PREVIEW_SCALE});
42
+ transition:
43
+ opacity ${MEDIA_CONTENT_IMAGE_FADE_DURATION_MS}ms ease,
44
+ filter ${MEDIA_CONTENT_IMAGE_FADE_DURATION_MS}ms ease;
45
+ `;
46
+ export const StyledMediaContentImage = styled(StyledMediaContentLayer)`
47
+ background-color: ${({
48
+ theme
49
+ }) => theme['101']};
50
+ box-shadow: 0 0 0 1px
51
+ rgba(${({
52
+ theme
53
+ }) => theme['009-rgb']}, 0.08) inset;
54
+ z-index: 2;
55
+ transition: opacity ${MEDIA_CONTENT_IMAGE_FADE_DURATION_MS}ms ease;
30
56
  `;
31
57
  export const StyledMediaContentVideo = styled.video`
32
58
  background-color: ${({
@@ -36,8 +62,12 @@ export const StyledMediaContentVideo = styled.video`
36
62
  rgba(${({
37
63
  theme
38
64
  }) => theme['009-rgb']}, 0.08) inset;
65
+ position: absolute;
66
+ inset: 0;
39
67
  width: 100%;
68
+ height: 100%;
40
69
  object-fit: cover;
70
+ pointer-events: none;
41
71
  `;
42
72
  export const StyledMediaContentPlayIcon = styled.div`
43
73
  position: absolute;
@@ -1 +1 @@
1
- {"version":3,"file":"MediaContent.styles.js","names":["styled","StyledMediaContentVideoWrapper","div","$ratio","StyledMediaContentImageWrapper","StyledMediaContentImage","img","theme","StyledMediaContentVideo","video","StyledMediaContentPlayIcon"],"sources":["../../../../src/components/media-content/MediaContent.styles.ts"],"sourcesContent":["import type { WithTheme } from '@chayns-components/core';\nimport styled from 'styled-components';\n\nexport const StyledMediaContentVideoWrapper = styled.div<{ $ratio: number }>`\n display: flex;\n width: 100%;\n height: 100%;\n aspect-ratio: ${({ $ratio }) => $ratio};\n`;\n\nexport const StyledMediaContentImageWrapper = styled.div<{ $ratio: number }>`\n display: flex;\n width: 100%;\n height: 100%;\n aspect-ratio: ${({ $ratio }) => $ratio};\n`;\n\ntype StyledMediaContentVideoProps = WithTheme<unknown>;\n\ntype StyledMediaContentImageProps = WithTheme<unknown>;\n\nexport const StyledMediaContentImage = styled.img<StyledMediaContentImageProps>`\n background-color: ${({ theme }: StyledMediaContentImageProps) => theme['101']};\n box-shadow: 0 0 0 1px\n rgba(${({ theme }: StyledMediaContentImageProps) => theme['009-rgb']}, 0.08) inset;\n z-index: 1;\n width: 100%;\n height: 100%;\n object-fit: cover;\n`;\n\nexport const StyledMediaContentVideo = styled.video<StyledMediaContentVideoProps>`\n background-color: ${({ theme }: StyledMediaContentVideoProps) => theme['101']};\n box-shadow: 0 0 0 1px\n rgba(${({ theme }: StyledMediaContentVideoProps) => theme['009-rgb']}, 0.08) inset;\n width: 100%;\n object-fit: cover;\n`;\n\nexport const StyledMediaContentPlayIcon = styled.div`\n position: absolute;\n z-index: 2;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n`;\n"],"mappings":"AACA,OAAOA,MAAM,MAAM,mBAAmB;AAEtC,OAAO,MAAMC,8BAA8B,GAAGD,MAAM,CAACE,GAAuB;AAC5E;AACA;AACA;AACA,oBAAoB,CAAC;EAAEC;AAAO,CAAC,KAAKA,MAAM;AAC1C,CAAC;AAED,OAAO,MAAMC,8BAA8B,GAAGJ,MAAM,CAACE,GAAuB;AAC5E;AACA;AACA;AACA,oBAAoB,CAAC;EAAEC;AAAO,CAAC,KAAKA,MAAM;AAC1C,CAAC;AAMD,OAAO,MAAME,uBAAuB,GAAGL,MAAM,CAACM,GAAiC;AAC/E,wBAAwB,CAAC;EAAEC;AAAoC,CAAC,KAAKA,KAAK,CAAC,KAAK,CAAC;AACjF;AACA,eAAe,CAAC;EAAEA;AAAoC,CAAC,KAAKA,KAAK,CAAC,SAAS,CAAC;AAC5E;AACA;AACA;AACA;AACA,CAAC;AAED,OAAO,MAAMC,uBAAuB,GAAGR,MAAM,CAACS,KAAmC;AACjF,wBAAwB,CAAC;EAAEF;AAAoC,CAAC,KAAKA,KAAK,CAAC,KAAK,CAAC;AACjF;AACA,eAAe,CAAC;EAAEA;AAAoC,CAAC,KAAKA,KAAK,CAAC,SAAS,CAAC;AAC5E;AACA;AACA,CAAC;AAED,OAAO,MAAMG,0BAA0B,GAAGV,MAAM,CAACE,GAAG;AACpD;AACA;AACA;AACA;AACA;AACA,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"MediaContent.styles.js","names":["styled","MEDIA_CONTENT_IMAGE_FADE_DURATION_MS","MEDIA_CONTENT_PREVIEW_BLUR","MEDIA_CONTENT_PREVIEW_SCALE","StyledMediaContentVideoWrapper","div","$ratio","StyledMediaContentImageWrapper","StyledMediaContentLayer","img","StyledMediaContentPreviewImage","theme","StyledMediaContentImage","StyledMediaContentVideo","video","StyledMediaContentPlayIcon"],"sources":["../../../../src/components/media-content/MediaContent.styles.ts"],"sourcesContent":["import type { WithTheme } from '@chayns-components/core';\nimport styled from 'styled-components';\nimport {\n MEDIA_CONTENT_IMAGE_FADE_DURATION_MS,\n MEDIA_CONTENT_PREVIEW_BLUR,\n MEDIA_CONTENT_PREVIEW_SCALE,\n} from './MediaContent.constants';\n\nexport const StyledMediaContentVideoWrapper = styled.div<{ $ratio: number }>`\n display: flex;\n position: relative;\n overflow: hidden;\n width: 100%;\n height: 100%;\n aspect-ratio: ${({ $ratio }) => $ratio};\n`;\n\nexport const StyledMediaContentImageWrapper = styled.div<{ $ratio: number }>`\n display: flex;\n position: relative;\n overflow: hidden;\n width: 100%;\n height: 100%;\n aspect-ratio: ${({ $ratio }) => $ratio};\n`;\n\ntype StyledMediaContentVideoProps = WithTheme<unknown>;\n\ntype StyledMediaContentImageProps = WithTheme<unknown>;\n\nconst StyledMediaContentLayer = styled.img<StyledMediaContentImageProps>`\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n pointer-events: none;\n`;\n\nexport const StyledMediaContentPreviewImage = styled(StyledMediaContentLayer)`\n background-color: ${({ theme }: StyledMediaContentImageProps) => theme['101']};\n box-shadow: 0 0 0 1px\n rgba(${({ theme }: StyledMediaContentImageProps) => theme['009-rgb']}, 0.08) inset;\n z-index: 1;\n filter: ${MEDIA_CONTENT_PREVIEW_BLUR};\n transform: scale(${MEDIA_CONTENT_PREVIEW_SCALE});\n transition:\n opacity ${MEDIA_CONTENT_IMAGE_FADE_DURATION_MS}ms ease,\n filter ${MEDIA_CONTENT_IMAGE_FADE_DURATION_MS}ms ease;\n`;\n\nexport const StyledMediaContentImage = styled(StyledMediaContentLayer)`\n background-color: ${({ theme }: StyledMediaContentImageProps) => theme['101']};\n box-shadow: 0 0 0 1px\n rgba(${({ theme }: StyledMediaContentImageProps) => theme['009-rgb']}, 0.08) inset;\n z-index: 2;\n transition: opacity ${MEDIA_CONTENT_IMAGE_FADE_DURATION_MS}ms ease;\n`;\n\nexport const StyledMediaContentVideo = styled.video<StyledMediaContentVideoProps>`\n background-color: ${({ theme }: StyledMediaContentVideoProps) => theme['101']};\n box-shadow: 0 0 0 1px\n rgba(${({ theme }: StyledMediaContentVideoProps) => theme['009-rgb']}, 0.08) inset;\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n pointer-events: none;\n`;\n\nexport const StyledMediaContentPlayIcon = styled.div`\n position: absolute;\n z-index: 2;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n`;\n"],"mappings":"AACA,OAAOA,MAAM,MAAM,mBAAmB;AACtC,SACIC,oCAAoC,EACpCC,0BAA0B,EAC1BC,2BAA2B,QACxB,0BAA0B;AAEjC,OAAO,MAAMC,8BAA8B,GAAGJ,MAAM,CAACK,GAAuB;AAC5E;AACA;AACA;AACA;AACA;AACA,oBAAoB,CAAC;EAAEC;AAAO,CAAC,KAAKA,MAAM;AAC1C,CAAC;AAED,OAAO,MAAMC,8BAA8B,GAAGP,MAAM,CAACK,GAAuB;AAC5E;AACA;AACA;AACA;AACA;AACA,oBAAoB,CAAC;EAAEC;AAAO,CAAC,KAAKA,MAAM;AAC1C,CAAC;AAMD,MAAME,uBAAuB,GAAGR,MAAM,CAACS,GAAiC;AACxE;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AAED,OAAO,MAAMC,8BAA8B,GAAGV,MAAM,CAACQ,uBAAuB,CAAC;AAC7E,wBAAwB,CAAC;EAAEG;AAAoC,CAAC,KAAKA,KAAK,CAAC,KAAK,CAAC;AACjF;AACA,eAAe,CAAC;EAAEA;AAAoC,CAAC,KAAKA,KAAK,CAAC,SAAS,CAAC;AAC5E;AACA,cAAcT,0BAA0B;AACxC,uBAAuBC,2BAA2B;AAClD;AACA,kBAAkBF,oCAAoC;AACtD,iBAAiBA,oCAAoC;AACrD,CAAC;AAED,OAAO,MAAMW,uBAAuB,GAAGZ,MAAM,CAACQ,uBAAuB,CAAC;AACtE,wBAAwB,CAAC;EAAEG;AAAoC,CAAC,KAAKA,KAAK,CAAC,KAAK,CAAC;AACjF;AACA,eAAe,CAAC;EAAEA;AAAoC,CAAC,KAAKA,KAAK,CAAC,SAAS,CAAC;AAC5E;AACA,0BAA0BV,oCAAoC;AAC9D,CAAC;AAED,OAAO,MAAMY,uBAAuB,GAAGb,MAAM,CAACc,KAAmC;AACjF,wBAAwB,CAAC;EAAEH;AAAoC,CAAC,KAAKA,KAAK,CAAC,KAAK,CAAC;AACjF;AACA,eAAe,CAAC;EAAEA;AAAoC,CAAC,KAAKA,KAAK,CAAC,SAAS,CAAC;AAC5E;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AAED,OAAO,MAAMI,0BAA0B,GAAGf,MAAM,CAACK,GAAG;AACpD;AACA;AACA;AACA;AACA;AACA,CAAC","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"MediaContent.types.js","names":[],"sources":["../../../../src/components/media-content/MediaContent.types.ts"],"sourcesContent":["import type { FileItem } from '@chayns-components/core';\n\n/**\n * Props for the low-level uploaded media renderer shared by viewer and editor.\n */\nexport interface MediaContentProps {\n /**\n * Provides the uploaded media item that should be rendered.\n * @description\n * This low-level renderer accepts already known image or video data and does not handle upload-specific state.\n * @example\n * <MediaContent file={file.file} onClick={handleOpen} ratio={1} />\n */\n file: FileItem['file'];\n /**\n * Defines the aspect ratio that should be reserved for the media.\n * @description\n * The surrounding tile uses this value to reserve a deterministic media height before the asset finishes loading.\n * @example\n * <MediaContent file={file.file} onClick={handleOpen} ratio={1.5} />\n */\n ratio: number;\n /**\n * Is called when the media tile is selected.\n * @description\n * Use this callback to react to clicks on the rendered image or video tile.\n * @example\n * <MediaContent file={file.file} onClick={() => console.log('open')} ratio={1} />\n */\n onClick: () => void;\n /**\n * Defines the size of the video play icon.\n * @description\n * This prop only affects rendered videos. Image tiles ignore it.\n * @default 50\n * @example\n * <MediaContent file={file.file} onClick={handleOpen} playIconSize={30} ratio={1} />\n * @optional\n */\n playIconSize?: number;\n}\n"],"mappings":"","ignoreList":[]}
1
+ {"version":3,"file":"MediaContent.types.js","names":[],"sources":["../../../../src/components/media-content/MediaContent.types.ts"],"sourcesContent":["import type { FileItem } from '@chayns-components/core';\n\n/**\n * Props for the low-level uploaded media renderer shared by viewer and editor.\n */\nexport interface MediaContentProps {\n /**\n * Provides the uploaded media item that should be rendered.\n * @description\n * This low-level renderer accepts already known image or video data and does not handle upload-specific state.\n * @example\n * <MediaContent file={file.file} onClick={handleOpen} ratio={1} />\n */\n file: FileItem['file'];\n /**\n * Provides an optional preview source that can be displayed while the final media is still loading.\n * @description\n * This preview can be a base64 data URL or any low-resolution fallback image.\n * When provided, the component shows the preview first and swaps to the final image once it has finished loading.\n * @optional\n */\n previewUrl?: string;\n /**\n * Defines the aspect ratio that should be reserved for the media.\n * @description\n * The surrounding tile uses this value to reserve a deterministic media height before the asset finishes loading.\n * @example\n * <MediaContent file={file.file} onClick={handleOpen} ratio={1.5} />\n */\n ratio: number;\n /**\n * Controls whether the final media source may be loaded immediately.\n * @description\n * When set to `false`, only the preview source is rendered until this flag becomes `true`.\n * @default true\n * @optional\n */\n shouldLoadImages?: boolean;\n /**\n * Is called when the media tile is selected.\n * @description\n * Use this callback to react to clicks on the rendered image or video tile.\n * @example\n * <MediaContent file={file.file} onClick={() => console.log('open')} ratio={1} />\n */\n onClick: () => void;\n /**\n * Defines the size of the video play icon.\n * @description\n * This prop only affects rendered videos. Image tiles ignore it.\n * @default 50\n * @example\n * <MediaContent file={file.file} onClick={handleOpen} playIconSize={30} ratio={1} />\n * @optional\n */\n playIconSize?: number;\n}\n"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,71 @@
1
+ const IMAGE_SERVICE_ORIGINS = new Set(['https://tsimg.cloud', 'https://tsimg.space']);
2
+ const IMAGE_SERVICE_PARAM_PATTERN = /^(?:m(?:scale|crop|shortedgescale)|[whsbd]\d+)$/i;
3
+ const IMAGE_SERVICE_RESIZE_OVERSCAN = 1.25;
4
+ export const isVideoFile = file => 'thumbnailUrl' in file;
5
+ export const getMediaSourceUrl = file => file.url.replace('_0.mp4', '.mp4');
6
+ export const getMediaPreviewUrl = (file, previewUrl) => {
7
+ if (previewUrl) {
8
+ return previewUrl;
9
+ }
10
+ if (isVideoFile(file)) {
11
+ return file.thumbnailUrl;
12
+ }
13
+ return file.meta?.preview;
14
+ };
15
+ export const isImageServiceUrl = url => {
16
+ try {
17
+ return IMAGE_SERVICE_ORIGINS.has(new URL(url).origin);
18
+ } catch (_) {
19
+ return false;
20
+ }
21
+ };
22
+ export const hasImageServiceTransformParameters = url => {
23
+ if (!isImageServiceUrl(url)) {
24
+ return false;
25
+ }
26
+ try {
27
+ const urlObject = new URL(url);
28
+ const fileName = urlObject.pathname.split('/').pop();
29
+ if (!fileName) {
30
+ return false;
31
+ }
32
+ const extensionIndex = fileName.lastIndexOf('.');
33
+ const nameWithoutExtension = extensionIndex > -1 ? fileName.slice(0, extensionIndex) : fileName;
34
+ const parameterSegment = nameWithoutExtension.split('_').pop();
35
+ if (!parameterSegment || parameterSegment === nameWithoutExtension) {
36
+ return false;
37
+ }
38
+ return parameterSegment.split('-').every(parameter => IMAGE_SERVICE_PARAM_PATTERN.test(parameter));
39
+ } catch (_) {
40
+ return false;
41
+ }
42
+ };
43
+ const buildImageServiceParameterSegment = (size, devicePixelRatio) => {
44
+ const scaleFactor = Number.isFinite(devicePixelRatio) && devicePixelRatio > 0 ? devicePixelRatio : 1;
45
+ const width = Math.max(1, Math.ceil(size.width * scaleFactor * IMAGE_SERVICE_RESIZE_OVERSCAN));
46
+ const height = Math.max(1, Math.ceil(size.height * scaleFactor * IMAGE_SERVICE_RESIZE_OVERSCAN));
47
+ return `w${width}-h${height}`;
48
+ };
49
+ export const getResponsiveImageServiceUrl = (url, size, devicePixelRatio = 1) => {
50
+ if (!size || hasImageServiceTransformParameters(url) || !isImageServiceUrl(url)) {
51
+ return url;
52
+ }
53
+ try {
54
+ const urlObject = new URL(url);
55
+ const pathSegments = urlObject.pathname.split('/');
56
+ const fileName = pathSegments.pop();
57
+ if (!fileName) {
58
+ return url;
59
+ }
60
+ const extensionIndex = fileName.lastIndexOf('.');
61
+ const extension = extensionIndex > -1 ? fileName.slice(extensionIndex) : '';
62
+ const fileBaseName = extensionIndex > -1 ? fileName.slice(0, extensionIndex) : fileName;
63
+ const parameterSegment = buildImageServiceParameterSegment(size, devicePixelRatio);
64
+ pathSegments.push(`${fileBaseName}_${parameterSegment}${extension}`);
65
+ urlObject.pathname = pathSegments.join('/');
66
+ return urlObject.toString();
67
+ } catch (_) {
68
+ return url;
69
+ }
70
+ };
71
+ //# sourceMappingURL=MediaContent.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaContent.utils.js","names":["IMAGE_SERVICE_ORIGINS","Set","IMAGE_SERVICE_PARAM_PATTERN","IMAGE_SERVICE_RESIZE_OVERSCAN","isVideoFile","file","getMediaSourceUrl","url","replace","getMediaPreviewUrl","previewUrl","thumbnailUrl","meta","preview","isImageServiceUrl","has","URL","origin","_","hasImageServiceTransformParameters","urlObject","fileName","pathname","split","pop","extensionIndex","lastIndexOf","nameWithoutExtension","slice","parameterSegment","every","parameter","test","buildImageServiceParameterSegment","size","devicePixelRatio","scaleFactor","Number","isFinite","width","Math","max","ceil","height","getResponsiveImageServiceUrl","pathSegments","extension","fileBaseName","push","join","toString"],"sources":["../../../../src/components/media-content/MediaContent.utils.ts"],"sourcesContent":["import type { FileItem, Video } from '@chayns-components/core';\n\nexport type GalleryMediaFile = FileItem['file'];\n\nexport type MediaContentSize = {\n height: number;\n width: number;\n};\n\nconst IMAGE_SERVICE_ORIGINS = new Set(['https://tsimg.cloud', 'https://tsimg.space']);\nconst IMAGE_SERVICE_PARAM_PATTERN = /^(?:m(?:scale|crop|shortedgescale)|[whsbd]\\d+)$/i;\nconst IMAGE_SERVICE_RESIZE_OVERSCAN = 1.25;\n\nexport const isVideoFile = (file: GalleryMediaFile): file is Video => 'thumbnailUrl' in file;\n\nexport const getMediaSourceUrl = (file: GalleryMediaFile): string =>\n file.url.replace('_0.mp4', '.mp4');\n\nexport const getMediaPreviewUrl = (\n file: GalleryMediaFile,\n previewUrl?: string,\n): string | undefined => {\n if (previewUrl) {\n return previewUrl;\n }\n\n if (isVideoFile(file)) {\n return file.thumbnailUrl;\n }\n\n return file.meta?.preview;\n};\n\nexport const isImageServiceUrl = (url: string): boolean => {\n try {\n return IMAGE_SERVICE_ORIGINS.has(new URL(url).origin);\n } catch (_) {\n return false;\n }\n};\n\nexport const hasImageServiceTransformParameters = (url: string): boolean => {\n if (!isImageServiceUrl(url)) {\n return false;\n }\n\n try {\n const urlObject = new URL(url);\n const fileName = urlObject.pathname.split('/').pop();\n\n if (!fileName) {\n return false;\n }\n\n const extensionIndex = fileName.lastIndexOf('.');\n const nameWithoutExtension =\n extensionIndex > -1 ? fileName.slice(0, extensionIndex) : fileName;\n const parameterSegment = nameWithoutExtension.split('_').pop();\n\n if (!parameterSegment || parameterSegment === nameWithoutExtension) {\n return false;\n }\n\n return parameterSegment\n .split('-')\n .every((parameter) => IMAGE_SERVICE_PARAM_PATTERN.test(parameter));\n } catch (_) {\n return false;\n }\n};\n\nconst buildImageServiceParameterSegment = (size: MediaContentSize, devicePixelRatio: number) => {\n const scaleFactor =\n Number.isFinite(devicePixelRatio) && devicePixelRatio > 0 ? devicePixelRatio : 1;\n const width = Math.max(1, Math.ceil(size.width * scaleFactor * IMAGE_SERVICE_RESIZE_OVERSCAN));\n const height = Math.max(\n 1,\n Math.ceil(size.height * scaleFactor * IMAGE_SERVICE_RESIZE_OVERSCAN),\n );\n\n return `w${width}-h${height}`;\n};\n\nexport const getResponsiveImageServiceUrl = (\n url: string,\n size?: MediaContentSize,\n devicePixelRatio = 1,\n): string => {\n if (!size || hasImageServiceTransformParameters(url) || !isImageServiceUrl(url)) {\n return url;\n }\n\n try {\n const urlObject = new URL(url);\n const pathSegments = urlObject.pathname.split('/');\n const fileName = pathSegments.pop();\n\n if (!fileName) {\n return url;\n }\n\n const extensionIndex = fileName.lastIndexOf('.');\n const extension = extensionIndex > -1 ? fileName.slice(extensionIndex) : '';\n const fileBaseName = extensionIndex > -1 ? fileName.slice(0, extensionIndex) : fileName;\n const parameterSegment = buildImageServiceParameterSegment(size, devicePixelRatio);\n\n pathSegments.push(`${fileBaseName}_${parameterSegment}${extension}`);\n urlObject.pathname = pathSegments.join('/');\n\n return urlObject.toString();\n } catch (_) {\n return url;\n }\n};\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,62 @@
1
+ import { useEffect, useState } from 'react';
2
+ const MEDIA_CONTENT_SIZE_RESIZE_DEBOUNCE_MS = 100;
3
+ const getSizeFromElement = element => {
4
+ if (!element) {
5
+ return undefined;
6
+ }
7
+ const {
8
+ width,
9
+ height
10
+ } = element.getBoundingClientRect();
11
+ if (width <= 0 || height <= 0) {
12
+ return undefined;
13
+ }
14
+ return {
15
+ width,
16
+ height
17
+ };
18
+ };
19
+ const useMediaContentSize = element => {
20
+ const [size, setSize] = useState();
21
+ useEffect(() => {
22
+ if (!element) {
23
+ setSize(undefined);
24
+ return undefined;
25
+ }
26
+ let timeoutId;
27
+ const updateSize = () => {
28
+ const nextSize = getSizeFromElement(element);
29
+ if (!nextSize) {
30
+ setSize(undefined);
31
+ return;
32
+ }
33
+ if (timeoutId) {
34
+ clearTimeout(timeoutId);
35
+ }
36
+ timeoutId = setTimeout(() => {
37
+ setSize(nextSize);
38
+ }, MEDIA_CONTENT_SIZE_RESIZE_DEBOUNCE_MS);
39
+ };
40
+ updateSize();
41
+ if (typeof ResizeObserver === 'undefined') {
42
+ return () => {
43
+ if (timeoutId) {
44
+ clearTimeout(timeoutId);
45
+ }
46
+ };
47
+ }
48
+ const resizeObserver = new ResizeObserver(() => {
49
+ updateSize();
50
+ });
51
+ resizeObserver.observe(element);
52
+ return () => {
53
+ resizeObserver.disconnect();
54
+ if (timeoutId) {
55
+ clearTimeout(timeoutId);
56
+ }
57
+ };
58
+ }, [element]);
59
+ return size;
60
+ };
61
+ export default useMediaContentSize;
62
+ //# sourceMappingURL=useMediaContentSize.js.map