import { useControl, useField, type FieldName } from "@conform-to/react/future"; import { Field, type FieldProps } from "../field/Field"; import { isMediaImage, MediaPreview } from "../../media-preview"; import { Button } from "../../button/Button"; import { UploaderMock } from "./UploaderMock"; import { Media } from "./types"; type Props = Omit & { name: FieldName; mediaContainerClassName?: string; allowedTypes?: "image" | "audio" | "all-safe"; imageRatio?: number; }; export function FileField({ name, mediaContainerClassName, allowedTypes = "all-safe", imageRatio, id: forcedId, ...rest }: Props) { const field = useField(name); const id = forcedId ?? field.id; const itemErrors = Object.values(field.fieldErrors).flat(); const errors = field.errors ?? (itemErrors.length > 0 ? itemErrors : undefined); const control = useControl({ defaultValue: field.defaultValue, parse(payload) { if (typeof payload !== "string") { throw new Error("media input must return string"); } if (payload == null || payload === "") { return undefined; } return JSON.parse(payload); }, // appelé uniquement par control.change(value) (ex: onPick, le bouton de suppression) : // convertit le Media/null en string écrite dans l'input caché et déclenche l'event // "input" natif. N'est pas utilisé pour le defaultValue initial (déjà une string). serialize(value) { return typeof value !== "string" && value != null ? JSON.stringify(value) : value; }, }); const media = control.payload; return ( <> {media ? ( ) : ( { console.log("onPick", media); control.change(media); }} imageRatio={imageRatio} allowedTypes={allowedTypes} /> )} ); }