use-uploader.ts 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import { useEffect, useRef, useState } from 'react'
  2. type UploaderHookProps = {
  3. onFileChange: (file: File | null) => void
  4. containerRef: React.RefObject<HTMLDivElement>
  5. enabled?: boolean
  6. }
  7. export const useUploader = ({ onFileChange, containerRef, enabled = true }: UploaderHookProps) => {
  8. const [dragging, setDragging] = useState(false)
  9. const fileUploader = useRef<HTMLInputElement>(null)
  10. const handleDragEnter = (e: DragEvent) => {
  11. e.preventDefault()
  12. e.stopPropagation()
  13. if (e.dataTransfer?.types.includes('Files'))
  14. setDragging(true)
  15. }
  16. const handleDragOver = (e: DragEvent) => {
  17. e.preventDefault()
  18. e.stopPropagation()
  19. }
  20. const handleDragLeave = (e: DragEvent) => {
  21. e.preventDefault()
  22. e.stopPropagation()
  23. if (e.relatedTarget === null || !containerRef.current?.contains(e.relatedTarget as Node))
  24. setDragging(false)
  25. }
  26. const handleDrop = (e: DragEvent) => {
  27. e.preventDefault()
  28. e.stopPropagation()
  29. setDragging(false)
  30. if (!e.dataTransfer)
  31. return
  32. const files = [...e.dataTransfer.files]
  33. if (files.length > 0)
  34. onFileChange(files[0])
  35. }
  36. const fileChangeHandle = enabled
  37. ? (e: React.ChangeEvent<HTMLInputElement>) => {
  38. const file = e.target.files?.[0] || null
  39. onFileChange(file)
  40. }
  41. : null
  42. const removeFile = enabled
  43. ? () => {
  44. if (fileUploader.current)
  45. fileUploader.current.value = ''
  46. onFileChange(null)
  47. }
  48. : null
  49. useEffect(() => {
  50. if (!enabled)
  51. return
  52. const current = containerRef.current
  53. if (current) {
  54. current.addEventListener('dragenter', handleDragEnter)
  55. current.addEventListener('dragover', handleDragOver)
  56. current.addEventListener('dragleave', handleDragLeave)
  57. current.addEventListener('drop', handleDrop)
  58. }
  59. return () => {
  60. if (current) {
  61. current.removeEventListener('dragenter', handleDragEnter)
  62. current.removeEventListener('dragover', handleDragOver)
  63. current.removeEventListener('dragleave', handleDragLeave)
  64. current.removeEventListener('drop', handleDrop)
  65. }
  66. }
  67. }, [containerRef, enabled])
  68. return {
  69. dragging: enabled ? dragging : false,
  70. fileUploader,
  71. fileChangeHandle,
  72. removeFile,
  73. }
  74. }