| 1 | import { memo, useEffect, useState, type ReactNode } from "react"; |
| 2 | |
| 3 | import { createComposerImageThumbnail } from "../../lib/imageCompression"; |
| 4 | |
| 5 | /** Keep full-resolution image decoding out of composer rerenders. */ |
| 6 | export const ComposerImageThumbnail = memo(function ComposerImageThumbnail({ |
| 7 | file, |
| 8 | alt, |
| 9 | className, |
| 10 | fallback, |
| 11 | }: { |
| 12 | file: File; |
| 13 | alt: string; |
| 14 | className: string; |
| 15 | fallback: ReactNode; |
| 16 | }) { |
| 17 | const [preview, setPreview] = useState<{ file: File; src: string | null } | null>(null); |
| 18 | useEffect(() => { |
| 19 | let active = true; |
| 20 | void createComposerImageThumbnail(file).then((src) => { |
| 21 | if (active) setPreview({ file, src }); |
| 22 | }); |
| 23 | return () => { |
| 24 | active = false; |
| 25 | }; |
| 26 | }, [file]); |
| 27 | const src = preview?.file === file ? preview.src : null; |
| 28 | return src ? <img src={src} alt={alt} className={className} /> : fallback; |
| 29 | }); |