clean up code even further
This commit is contained in:
parent
2709312943
commit
43ae003c83
@ -1,12 +1,7 @@
|
|||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import { Textarea } from "../ui/textarea";
|
import { Textarea } from "../ui/textarea";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
|
import { addHighlight, getAdjustedCoordinates, removeHighlight } from "./utils";
|
||||||
function removeHighlight(element: HTMLElement) {
|
|
||||||
element.style.outline = "";
|
|
||||||
element.style.backgroundColor = "";
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface EditPopupProps {
|
interface EditPopupProps {
|
||||||
event: MouseEvent | null;
|
event: MouseEvent | null;
|
||||||
@ -24,50 +19,43 @@ const EditPopup: React.FC<EditPopupProps> = ({
|
|||||||
doUpdate,
|
doUpdate,
|
||||||
iframeRef,
|
iframeRef,
|
||||||
}) => {
|
}) => {
|
||||||
const [editText, setEditText] = useState("");
|
// Edit state
|
||||||
const [selectedElement, setSelectedElement] = useState<
|
const [selectedElement, setSelectedElement] = useState<
|
||||||
HTMLElement | undefined
|
HTMLElement | undefined
|
||||||
>(undefined);
|
>(undefined);
|
||||||
|
const [updateText, setUpdateText] = useState("");
|
||||||
|
|
||||||
|
// Popup state
|
||||||
const [popupVisible, setPopupVisible] = useState(false);
|
const [popupVisible, setPopupVisible] = useState(false);
|
||||||
const [popupPosition, setPopupPosition] = useState({ x: 0, y: 0 });
|
const [popupPosition, setPopupPosition] = useState({ x: 0, y: 0 });
|
||||||
|
|
||||||
const inSelectAndEditModeRef = useRef(inSelectAndEditMode); // Create a ref for the state
|
// Create a wrapper ref to store inSelectAndEditMode so the value is not stale
|
||||||
|
// in a event listener
|
||||||
|
const inSelectAndEditModeRef = useRef(inSelectAndEditMode);
|
||||||
|
|
||||||
|
// Textarea ref for focusing
|
||||||
const textareaRef = useRef<HTMLTextAreaElement | null>(null);
|
const textareaRef = useRef<HTMLTextAreaElement | null>(null);
|
||||||
|
|
||||||
function updateHighlight(targetElement: HTMLElement) {
|
function onUpdate(updateText: string) {
|
||||||
setSelectedElement((prev) => {
|
// Perform the update
|
||||||
// Remove style from previous element
|
|
||||||
if (prev) {
|
|
||||||
removeHighlight(prev);
|
|
||||||
}
|
|
||||||
// Add style to new element
|
|
||||||
targetElement.style.outline = "2px dashed #1846db";
|
|
||||||
targetElement.style.backgroundColor = "#bfcbf5";
|
|
||||||
return targetElement;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleEditSubmit(editText: string) {
|
|
||||||
doUpdate(
|
doUpdate(
|
||||||
editText,
|
updateText,
|
||||||
selectedElement ? removeHighlight(selectedElement) : selectedElement
|
selectedElement ? removeHighlight(selectedElement) : selectedElement
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Unselect the element
|
||||||
setSelectedElement(undefined);
|
setSelectedElement(undefined);
|
||||||
|
|
||||||
|
// Hide the popup
|
||||||
setPopupVisible(false);
|
setPopupVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the ref whenever the state changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (popupVisible && textareaRef.current) {
|
inSelectAndEditModeRef.current = inSelectAndEditMode;
|
||||||
textareaRef.current.focus();
|
}, [inSelectAndEditMode]);
|
||||||
}
|
|
||||||
}, [popupVisible]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!popupVisible) {
|
|
||||||
setEditText("");
|
|
||||||
}
|
|
||||||
}, [popupVisible, setEditText]);
|
|
||||||
|
|
||||||
|
// Remove highlight and reset state when not in select and edit mode
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!inSelectAndEditMode) {
|
if (!inSelectAndEditMode) {
|
||||||
if (selectedElement) removeHighlight(selectedElement);
|
if (selectedElement) removeHighlight(selectedElement);
|
||||||
@ -76,48 +64,47 @@ const EditPopup: React.FC<EditPopupProps> = ({
|
|||||||
}
|
}
|
||||||
}, [inSelectAndEditMode, selectedElement]);
|
}, [inSelectAndEditMode, selectedElement]);
|
||||||
|
|
||||||
|
// Handle the click event
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Return if not in select and edit mode
|
// Return if not in select and edit mode
|
||||||
if (!inSelectAndEditModeRef.current || !event) {
|
if (!inSelectAndEditModeRef.current || !event) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { clientX, clientY } = event;
|
|
||||||
|
|
||||||
// Prevent default to avoid issues like label clicks triggering textareas, etc.
|
// Prevent default to avoid issues like label clicks triggering textareas, etc.
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
const targetElement = event.target as HTMLElement;
|
const targetElement = event.target as HTMLElement;
|
||||||
|
|
||||||
// Return if no target element
|
// Return if no target element
|
||||||
if (!targetElement) {
|
if (!targetElement) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Highlight the selected element
|
// Highlight and set the selected element
|
||||||
updateHighlight(targetElement);
|
setSelectedElement((prev) => {
|
||||||
|
// Remove style from previous element
|
||||||
|
if (prev) {
|
||||||
|
removeHighlight(prev);
|
||||||
|
}
|
||||||
|
return addHighlight(targetElement);
|
||||||
|
});
|
||||||
|
|
||||||
// Show popup at click position, slightly offset to be right under the cursor
|
// Calculate adjusted coordinates
|
||||||
setPopupVisible(false);
|
const adjustedCoordinates = getAdjustedCoordinates(
|
||||||
|
event.clientX,
|
||||||
|
event.clientY,
|
||||||
|
iframeRef.current?.getBoundingClientRect()
|
||||||
|
);
|
||||||
|
|
||||||
// Calculate offsets
|
// Show the popup at the click position
|
||||||
const rect = iframeRef.current?.getBoundingClientRect();
|
|
||||||
const offsetX = rect ? rect.left : 0;
|
|
||||||
const offsetY = rect ? rect.top : 0;
|
|
||||||
|
|
||||||
// Adjust for scale
|
|
||||||
const scale = 1; // the scale factor applied to the iframe
|
|
||||||
const scaledX = clientX / scale + offsetX;
|
|
||||||
const scaledY = clientY / scale + offsetY;
|
|
||||||
|
|
||||||
setPopupPosition({ x: scaledX, y: scaledY });
|
|
||||||
setPopupVisible(true);
|
setPopupVisible(true);
|
||||||
}, [event]);
|
setPopupPosition({ x: adjustedCoordinates.x, y: adjustedCoordinates.y });
|
||||||
|
|
||||||
// Update the ref whenever the state changes
|
// Reset the update text
|
||||||
useEffect(() => {
|
setUpdateText("");
|
||||||
inSelectAndEditModeRef.current = inSelectAndEditMode;
|
|
||||||
}, [inSelectAndEditMode]);
|
// Focus the textarea
|
||||||
|
textareaRef.current?.focus();
|
||||||
|
}, [event, iframeRef]);
|
||||||
|
|
||||||
if (!popupVisible) return;
|
if (!popupVisible) return;
|
||||||
|
|
||||||
@ -128,12 +115,12 @@ const EditPopup: React.FC<EditPopupProps> = ({
|
|||||||
>
|
>
|
||||||
<Textarea
|
<Textarea
|
||||||
ref={textareaRef}
|
ref={textareaRef}
|
||||||
value={editText}
|
value={updateText}
|
||||||
onChange={(e) => setEditText(e.target.value)}
|
onChange={(e) => setUpdateText(e.target.value)}
|
||||||
placeholder="Tell the AI what to change about this element..."
|
placeholder="Tell the AI what to change about this element..."
|
||||||
/>
|
/>
|
||||||
<div className="flex justify-end mt-2">
|
<div className="flex justify-end mt-2">
|
||||||
<Button onClick={() => handleEditSubmit(editText)}>Update</Button>
|
<Button onClick={() => onUpdate(updateText)}>Update</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
24
frontend/src/components/select-and-edit/utils.ts
Normal file
24
frontend/src/components/select-and-edit/utils.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
export function removeHighlight(element: HTMLElement) {
|
||||||
|
element.style.outline = "";
|
||||||
|
element.style.backgroundColor = "";
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addHighlight(element: HTMLElement) {
|
||||||
|
element.style.outline = "2px dashed #1846db";
|
||||||
|
element.style.backgroundColor = "#bfcbf5";
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAdjustedCoordinates(
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
rect: DOMRect | undefined
|
||||||
|
) {
|
||||||
|
const offsetX = rect ? rect.left : 0;
|
||||||
|
const offsetY = rect ? rect.top : 0;
|
||||||
|
|
||||||
|
// Adjust for scale
|
||||||
|
const scale = 1; // the scale factor applied to the iframe
|
||||||
|
return { x: x / scale + offsetX, y: y / scale + offsetY };
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user