file-view-pdf.tsx 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import { FC, useCallback } from 'react'
  2. import useIsMounted from '@/shared/hooks/use-is-mounted'
  3. import { useFileTreePathContext } from '@/features/file-tree/contexts/file-tree-path'
  4. import { debugConsole } from '@/utils/debugging'
  5. const FileViewPdf: FC<{
  6. fileId: string
  7. onLoad: () => void
  8. onError: () => void
  9. }> = ({ fileId, onLoad, onError }) => {
  10. const mountedRef = useIsMounted()
  11. const { previewByPath, pathInFolder } = useFileTreePathContext()
  12. const handleContainer = useCallback(
  13. async (element: HTMLDivElement | null) => {
  14. if (element) {
  15. const { PDFJS } = await import(
  16. '../../pdf-preview/util/pdf-js-versions'
  17. ).then(m => m.default as any)
  18. // bail out if loading PDF.js took too long
  19. if (!mountedRef.current) {
  20. onError()
  21. return
  22. }
  23. const path = pathInFolder(fileId)
  24. const preview = path ? previewByPath(path) : null
  25. if (!preview) {
  26. onError()
  27. return
  28. }
  29. const pdf = await PDFJS.getDocument(preview.url).promise
  30. // bail out if loading the PDF took too long
  31. if (!mountedRef.current) {
  32. onError()
  33. return
  34. }
  35. element.textContent = '' // ensure the element is empty
  36. const scale = window.devicePixelRatio || 1
  37. for (let i = 1; i <= pdf.numPages; i++) {
  38. const page = await pdf.getPage(i)
  39. const viewport = page.getViewport({ scale })
  40. const canvas = document.createElement('canvas')
  41. canvas.classList.add('pdf-page')
  42. canvas.width = viewport.width
  43. canvas.height = viewport.height
  44. canvas.style.width = `${viewport.width / scale}px`
  45. canvas.style.height = `${viewport.height / scale}px`
  46. element.append(canvas)
  47. page.render({
  48. canvasContext: canvas.getContext('2d'),
  49. viewport,
  50. })
  51. }
  52. onLoad()
  53. return () => {
  54. pdf.cleanup().catch(debugConsole.error)
  55. pdf.destroy()
  56. }
  57. }
  58. },
  59. [mountedRef, pathInFolder, fileId, previewByPath, onLoad, onError]
  60. )
  61. return <div className="file-view-pdf" ref={handleContainer} />
  62. }
  63. export default FileViewPdf