uploader.tsx 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. import type { ChangeEvent, FC } from 'react'
  2. import { useState } from 'react'
  3. import { useLocalFileUploader } from './hooks'
  4. import type { ImageFile } from '@/types/app'
  5. import { ALLOW_FILE_EXTENSIONS } from '@/types/app'
  6. type UploaderProps = {
  7. children: (hovering: boolean) => JSX.Element
  8. onUpload: (imageFile: ImageFile) => void
  9. limit?: number
  10. disabled?: boolean
  11. }
  12. const Uploader: FC<UploaderProps> = ({
  13. children,
  14. onUpload,
  15. limit,
  16. disabled,
  17. }) => {
  18. const [hovering, setHovering] = useState(false)
  19. const { handleLocalFileUpload } = useLocalFileUploader({ limit, onUpload, disabled })
  20. const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
  21. const file = e.target.files?.[0]
  22. if (!file)
  23. return
  24. handleLocalFileUpload(file)
  25. }
  26. return (
  27. <div
  28. className='relative'
  29. onMouseEnter={() => setHovering(true)}
  30. onMouseLeave={() => setHovering(false)}
  31. >
  32. {children(hovering)}
  33. <input
  34. className={`
  35. absolute block inset-0 opacity-0 text-[0] w-full
  36. ${disabled ? 'cursor-not-allowed' : 'cursor-pointer'}
  37. `}
  38. onClick={e => (e.target as HTMLInputElement).value = ''}
  39. type='file'
  40. accept={ALLOW_FILE_EXTENSIONS.map(ext => `.${ext}`).join(',')}
  41. onChange={handleChange}
  42. disabled={disabled}
  43. />
  44. </div>
  45. )
  46. }
  47. export default Uploader