testeranto
Version:
the AI powered BDD test framework for typescript projects
120 lines (119 loc) • 6.36 kB
JavaScript
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useState, useRef, useCallback } from "react";
import { Button, ButtonGroup } from "react-bootstrap";
export const GenericPreview = ({ onTreeUpdate, xmlTree = {
id: "root",
type: "root",
attributes: {},
children: [],
}, selectedNodeId = null, hiddenNodes = new Set(), renderPreview = (node, isSelected, eventHandlers, onTreeUpdate) => {
console.error("Default renderPreview called - this should be overridden");
return (React.createElement("div", { style: {
border: isSelected ? "2px solid blue" : "1px solid gray",
padding: "4px",
} },
"Default preview for: ",
node.type));
}, }) => {
// Add a check to ensure xmlTree is defined
console.log("GenericPreview props:", {
xmlTree,
selectedNodeId,
hiddenNodes,
renderPreview,
onTreeUpdate
});
if (!xmlTree) {
console.error("xmlTree is undefined in GenericPreview");
return React.createElement("div", null, "No XML tree data available");
}
const [scale, setScale] = useState(1);
const [position, setPosition] = useState({ x: 0, y: 0 });
const [isPanning, setIsPanning] = useState(false);
const [startPanPoint, setStartPanPoint] = useState({ x: 0, y: 0 });
const previewRef = useRef(null);
// Always render the preview using the root xmlTree, not individual nodes
// This ensures we only get one preview rendered
const previewElement = React.useMemo(() => {
try {
const isSelected = selectedNodeId === xmlTree.id;
const eventHandlers = {};
return renderPreview(xmlTree, isSelected, eventHandlers, onTreeUpdate);
}
catch (error) {
console.error("Error in renderPreview:", error);
return (React.createElement("div", { style: { border: "1px solid red", padding: "4px", margin: "2px" } }, "Error rendering preview"));
}
}, [xmlTree, selectedNodeId, renderPreview, onTreeUpdate]);
// Handle mouse events for panning
const handleMouseDown = useCallback((e) => {
if (e.button === 1 || (e.button === 0 && e.altKey)) {
// Middle click or Alt + Left click
e.preventDefault();
setIsPanning(true);
setStartPanPoint({
x: e.clientX - position.x,
y: e.clientY - position.y,
});
}
}, [position]);
const handleMouseMove = useCallback((e) => {
if (isPanning) {
setPosition({
x: e.clientX - startPanPoint.x,
y: e.clientY - startPanPoint.y,
});
}
}, [isPanning, startPanPoint]);
const handleMouseUp = useCallback(() => {
setIsPanning(false);
}, []);
const handleWheel = useCallback((e) => {
e.preventDefault();
const delta = -e.deltaY * 0.01;
setScale((prevScale) => Math.max(0.1, Math.min(5, prevScale + delta)));
}, []);
const resetView = useCallback(() => {
setScale(1);
setPosition({ x: 0, y: 0 });
}, []);
// Check if we're rendering SVG content (root node is svg)
let isSVG = false;
try {
isSVG = xmlTree.type === "svg";
}
catch (error) {
console.error("Error checking if xmlTree is SVG:", error);
return (React.createElement("div", { className: "border rounded p-3 d-flex justify-content-center align-items-center", style: { height: "400px", background: "#f8f9fa" } }, "Error: Invalid XML tree structure"));
}
// For SVG, we need to handle the transform differently
if (isSVG) {
return (React.createElement("div", { className: "border rounded p-3 d-flex justify-content-center align-items-center position-relative", style: { height: "400px", overflow: "hidden" }, ref: previewRef, onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, onMouseUp: handleMouseUp, onMouseLeave: handleMouseUp, onWheel: handleWheel },
React.createElement("div", { className: "position-absolute top-0 end-0 m-2" },
React.createElement(ButtonGroup, { size: "sm" },
React.createElement(Button, { variant: "outline-secondary", onClick: () => setScale((s) => Math.min(5, s + 0.1)) }, "+"),
React.createElement(Button, { variant: "outline-secondary", onClick: () => setScale((s) => Math.max(0.1, s - 0.1)) }, "-"),
React.createElement(Button, { variant: "outline-secondary", onClick: resetView }, "Reset"))),
React.createElement("div", { style: {
cursor: isPanning ? "grabbing" : scale !== 1 ? "grab" : "default",
transform: `scale(${scale}) translate(${position.x}px, ${position.y}px)`,
transformOrigin: "center center",
transition: isPanning ? "none" : "transform 0.1s ease",
} }, previewElement)));
}
// For non-SVG content (HTML/bootstrap), use a different approach
return (React.createElement("div", { className: "border rounded p-3 position-relative", style: { height: "400px", overflow: "hidden" }, ref: previewRef, onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, onMouseUp: handleMouseUp, onMouseLeave: handleMouseUp, onWheel: handleWheel },
React.createElement("div", { className: "position-absolute top-0 end-0 m-2" },
React.createElement(ButtonGroup, { size: "sm" },
React.createElement(Button, { variant: "outline-secondary", onClick: () => setScale((s) => Math.min(5, s + 0.1)) }, "+"),
React.createElement(Button, { variant: "outline-secondary", onClick: () => setScale((s) => Math.max(0.1, s - 0.1)) }, "-"),
React.createElement(Button, { variant: "outline-secondary", onClick: resetView }, "Reset"))),
React.createElement("div", { style: {
cursor: isPanning ? "grabbing" : scale !== 1 ? "grab" : "default",
transform: `scale(${scale}) translate(${position.x}px, ${position.y}px)`,
transformOrigin: "0 0",
transition: isPanning ? "none" : "transform 0.1s ease",
height: "100%",
} }, previewElement)));
};