freshyo/packages/web-components/src/components/image-uploader-neo.tsx
2026-09-06 16:14:54 +05:30

92 lines
2.7 KiB
TypeScript

import React, { useRef } from 'react'
import { cn } from '../lib/utils'
import { Plus, X } from 'lucide-react'
import type { ImageUploaderNeoItem, ImageUploaderNeoPayload, ImageUploaderNeoProps } from '@packages/shared'
import { div } from './my-touchable-opacity'
export type { ImageUploaderNeoItem, ImageUploaderNeoPayload } from '@packages/shared'
function usePickImage({
multiple,
}: {
multiple: boolean
}): () => void {
const inputRef = useRef<HTMLInputElement | null>(null)
return () => {
if (!inputRef.current) {
const input = document.createElement('input')
input.type = 'file'
input.accept = 'image/*'
input.multiple = multiple
input.onchange = () => {
const files = Array.from(input.files || [])
// We just trigger the native picker; actual handling is in the parent
}
inputRef.current = input
}
inputRef.current.click()
}
}
export function ImageUploaderNeo({
images,
onImageAdd,
onImageRemove,
allowMultiple = true,
}: ImageUploaderNeoProps) {
const totalCount = images.length
const handleFileInput = (e: React.ChangeEvent<HTMLInputElement>) => {
const files = Array.from(e.target.files || [])
if (files.length === 0) return
const payloads: ImageUploaderNeoPayload[] = files.map((file) => ({
url: URL.createObjectURL(file),
mimeType: file.type,
}))
onImageAdd(payloads)
// Reset input so same file can be picked again
e.target.value = ''
}
return (
<div className="mb-4">
<div className="flex flex-wrap gap-2">
{images.map((image, index) => (
<div key={index} className="relative w-1/3 aspect-square">
<img
src={image.imgUrl}
alt={`Upload ${index + 1}`}
className="h-full w-full rounded object-cover"
/>
<div
onClick={() =>
onImageRemove({
url: image.imgUrl,
mimeType: image.mimeType ?? null,
})
}
className="absolute right-1 top-1 rounded-full bg-red-500 p-1 text-white"
>
<X className="h-3 w-3" />
</div>
</div>
))}
{(!allowMultiple || totalCount < 1) && (
<label className="flex aspect-square w-1/3 cursor-pointer items-center justify-center rounded bg-gray-200 opacity-75 hover:opacity-100">
<Plus className="h-8 w-8 text-gray-600" />
<input
type="file"
accept="image/*"
multiple={allowMultiple}
onChange={handleFileInput}
className="hidden"
/>
</label>
)}
</div>
</div>
)
}