feat: improve cropper with form integration support

Pass cropped file output via onValueChange and handle external
value resets for form clear/reset flows.
This commit is contained in:
2026-06-07 23:05:07 +00:00 Unverified
parent dcaa8a88a5
commit 91a71e70fc
+34 -2
View File
@@ -85,7 +85,13 @@ async function getCroppedImg(
}
}
export default function Component() {
export default function Component({
value,
onValueChange,
}: {
value?: File | undefined;
onValueChange?: (value: File | undefined) => void;
}) {
const [
{ files, isDragging },
{
@@ -156,7 +162,15 @@ export default function Component() {
// 4. Set the final avatar state to the NEW URL
setFinalImageUrl(newFinalUrl);
// 5. Close the dialog (don't remove the file yet)
// 5. Create a File from the blob and pass it to the form
const croppedFile = new File(
[croppedBlob],
files[0]?.file.name || "cropped-image.jpg",
{ type: croppedBlob.type },
);
onValueChange?.(croppedFile);
// 6. Close the dialog (don't remove the file yet)
setIsDialogOpen(false);
} catch (error) {
console.error("Error during apply:", error);
@@ -170,6 +184,7 @@ export default function Component() {
URL.revokeObjectURL(finalImageUrl);
}
setFinalImageUrl(null);
onValueChange?.(undefined);
};
useEffect(() => {
@@ -194,6 +209,23 @@ export default function Component() {
previousFileIdRef.current = fileId;
}, [fileId]); // Depend only on fileId
// Reset cropper when value is cleared externally (e.g., form reset)
const previousValueRef = useRef(value);
// biome-ignore lint/correctness/useExhaustiveDependencies: only fire on value change
useEffect(() => {
const wasSet = !!previousValueRef.current;
const isBlank = !value;
if (wasSet && isBlank) {
if (finalImageUrl) {
URL.revokeObjectURL(finalImageUrl);
}
setFinalImageUrl(null);
setCroppedAreaPixels(null);
setZoom(1);
}
previousValueRef.current = value;
}, [value]);
return (
<>
<div className="relative inline-flex">