diff --git a/packages/interface/src/components/ImageUpload.tsx b/packages/interface/src/components/ImageUpload.tsx index 09f7c911..28e56e33 100644 --- a/packages/interface/src/components/ImageUpload.tsx +++ b/packages/interface/src/components/ImageUpload.tsx @@ -1,82 +1,94 @@ import { useMutation } from "@tanstack/react-query"; import clsx from "clsx"; import { ImageIcon } from "lucide-react"; -import { type ComponentProps, useRef, useCallback } from "react"; +import { type ComponentProps, ElementType, forwardRef, useRef, useCallback } from "react"; import { Controller, useFormContext } from "react-hook-form"; import { toast } from "sonner"; import { IconButton } from "~/components/ui/Button"; +import { PolymorphicRef } from "./ui"; + export interface IImageUploadProps extends ComponentProps<"img"> { name?: string; maxSize?: number; } -export const ImageUpload = ({ - name = "", - maxSize = 1024 * 1024, // 1 MB - className, -}: IImageUploadProps): JSX.Element => { - const ref = useRef(null); - const { control } = useFormContext(); - - const select = useMutation({ - mutationFn: async (file: File) => { - if (file.size >= maxSize) { - toast.error("Image too large", { - description: `The image to selected is: ${(file.size / 1024).toFixed(2)} / ${(maxSize / 1024).toFixed(2)} kb`, - }); - throw new Error("IMAGE_TOO_LARGE"); - } +export const ImageUpload = forwardRef( + ( + { + name = "", + maxSize = 1024 * 1024, // 1 MB + className, + }: IImageUploadProps, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + ref: PolymorphicRef, + ): JSX.Element => { + const internalRef = useRef(null); + const { control } = useFormContext(); - return Promise.resolve(URL.createObjectURL(file)); - }, - }); + const select = useMutation({ + mutationFn: async (file: File) => { + if (file.size >= maxSize) { + toast.error("Image too large", { + description: `The image to selected is: ${(file.size / 1024).toFixed(2)} / ${(maxSize / 1024).toFixed(2)} kb`, + }); + throw new Error("IMAGE_TOO_LARGE"); + } - const onClickIconButton = useCallback((e: React.MouseEvent) => { - e.preventDefault(); - }, []); + return Promise.resolve(URL.createObjectURL(file)); + }, + }); - return ( - ( - // eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events -
ref.current?.click()} - > - + const onClickIconButton = useCallback((e: React.MouseEvent) => { + e.preventDefault(); + }, []); + return ( + ( + // eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events
{ + internalRef.current?.click(); }} - /> + > + - { - const [file] = event.target.files ?? []; - if (file) { - select.mutate(file, { - onSuccess: (objectUrl) => { - onChange(objectUrl); - }, - }); - } - }} - /> -
- )} - rules={{ required: "Recipe picture is required" }} - /> - ); -}; +
+ + { + const [file] = event.target.files ?? []; + if (file) { + select.mutate(file, { + onSuccess: (objectUrl) => { + onChange(objectUrl); + }, + }); + } + }} + /> +
+ )} + rules={{ required: "Recipe picture is required" }} + /> + ); + }, +); + +ImageUpload.displayName = "ImageUpload";