import React, { useState, useRef, useEffect } from "react"; import { createPortal } from "react-dom"; import { Upload, Trash2, AlignLeft, AlignCenter, AlignRight, Image as ImageIcon, CornerDownRight, X } from "lucide-react"; export default function InlineImageEditor({ field, onUpdate, viewMode, setIsDirty, children }) { const [isEditing, setIsEditing] = useState(false); const [toolbarPosition, setToolbarPosition] = useState({ top: 0, left: 0 }); const [showCustomSizePopover, setShowCustomSizePopover] = useState(false); // the reference builder keys read by the canvas and the published form: imageCustomWidth / imageCustomHeight (older // imageWidth / imageHeight are read as a fallback). const [customWidth, setCustomWidth] = useState(field.imageCustomWidth || field.imageWidth || 400); const [customHeight, setCustomHeight] = useState(field.imageCustomHeight || field.imageHeight || 400); const [showRadius, setShowRadius] = useState(false); const containerRef = useRef(null); const toolbarRef = useRef(null); const customSizePopoverRef = useRef(null); useEffect(() => { if (isEditing && containerRef.current) { const updatePosition = () => { if (!containerRef.current) return; const rect = containerRef.current.getBoundingClientRect(); const toolbarWidth = 320; let left = rect.left + (rect.width / 2) - (toolbarWidth / 2); let top = rect.bottom + 8; if (left < 10) left = 10; if (left + toolbarWidth > window.innerWidth - 10) left = window.innerWidth - toolbarWidth - 10; if (top + 50 > window.innerHeight) top = rect.top - 50; setToolbarPosition({ top, left }); }; updatePosition(); window.addEventListener('scroll', updatePosition, true); window.addEventListener('resize', updatePosition); return () => { window.removeEventListener('scroll', updatePosition, true); window.removeEventListener('resize', updatePosition); }; } }, [isEditing]); useEffect(() => { const handleClickOutside = (e) => { if (!isEditing) return; if (e.target.closest && e.target.closest(".media-modal, .media-modal-backdrop")) return; if ( containerRef.current && !containerRef.current.contains(e.target) && toolbarRef.current && !toolbarRef.current.contains(e.target) && (!customSizePopoverRef.current || !customSizePopoverRef.current.contains(e.target)) ) { setIsEditing(false); setShowCustomSizePopover(false); } }; // Escape closes the toolbar (the WordPress media modal handles its own Escape). const onKey = (e) => { if (!isEditing || e.key !== "Escape") return; const mediaOpen = Array.from(document.querySelectorAll('.media-modal')).some((el) => el.getClientRects().length > 0); if (mediaOpen) return; e.stopPropagation(); setIsEditing(false); setShowCustomSizePopover(false); setShowRadius(false); }; document.addEventListener("mousedown", handleClickOutside); document.addEventListener("keydown", onKey, true); return () => { document.removeEventListener("mousedown", handleClickOutside); document.removeEventListener("keydown", onKey, true); }; }, [isEditing]); const handleOpenMediaLibrary = (e) => { e.stopPropagation(); if (window.wp && window.wp.media) { const mediaFrame = window.wp.media({ title: 'Select or Upload Form Image', button: { text: 'Use Image' }, multiple: false }); mediaFrame.on('select', () => { const attachment = mediaFrame.state().get('selection').first().toJSON(); if (attachment?.url) { if (setIsDirty) setIsDirty(true); onUpdate({ imageUrl: attachment.url, url: attachment.url, imageAltText: attachment.alt || attachment.title || '' }); } }); mediaFrame.open(); } else { const url = window.prompt("Enter Image URL:", field.imageUrl || field.url || ""); if (url !== null) { if (setIsDirty) setIsDirty(true); onUpdate({ imageUrl: url, url }); } } }; const handleAlignment = (alignment, e) => { e.stopPropagation(); if (setIsDirty) setIsDirty(true); onUpdate({ imageAlignment: alignment, alignment }); }; const handleSizeChange = (size, e) => { e.stopPropagation(); if (setIsDirty) setIsDirty(true); if (size === 'custom') { setShowCustomSizePopover(true); onUpdate({ imageSize: 'custom' }); } else { setShowCustomSizePopover(false); onUpdate({ imageSize: size }); } }; const handleApplyCustomSize = (e) => { e.stopPropagation(); if (setIsDirty) setIsDirty(true); onUpdate({ imageSize: 'custom', imageCustomWidth: parseInt(customWidth) || 400, imageCustomHeight: parseInt(customHeight) || 400 }); setShowCustomSizePopover(false); }; if (viewMode === 'preview') { return