"use client"; import { useCallback, useRef, type ReactNode } from "react"; import { NodeResizeControl, type ShouldResize } from "@xyflow/react"; import { NodeErrorBoundary } from "./node-error-boundary"; interface ResizeConfig { minWidth: number; minHeight: number; keepAspectRatio?: boolean; contentAware?: boolean; } const RESIZE_CONFIGS: Record = { frame: { minWidth: 200, minHeight: 150 }, group: { minWidth: 150, minHeight: 100 }, image: { minWidth: 100, minHeight: 80, keepAspectRatio: true }, asset: { minWidth: 100, minHeight: 80, keepAspectRatio: true }, "ai-image": { minWidth: 200, minHeight: 200 }, compare: { minWidth: 300, minHeight: 200 }, prompt: { minWidth: 240, minHeight: 200, contentAware: true }, text: { minWidth: 180, minHeight: 80, contentAware: true }, note: { minWidth: 160, minHeight: 80, contentAware: true }, }; const DEFAULT_CONFIG: ResizeConfig = { minWidth: 80, minHeight: 50, contentAware: true }; const CORNERS = [ "top-left", "top-right", "bottom-left", "bottom-right", ] as const; interface BaseNodeWrapperProps { nodeType: string; selected?: boolean; status?: string; statusMessage?: string; children: ReactNode; className?: string; } export default function BaseNodeWrapper({ nodeType, selected, status = "idle", statusMessage, children, className = "", }: BaseNodeWrapperProps) { const wrapperRef = useRef(null); const config = RESIZE_CONFIGS[nodeType] ?? DEFAULT_CONFIG; const statusStyles: Record = { idle: "", analyzing: "border-yellow-400 animate-pulse", clarifying: "border-amber-400", executing: "border-yellow-400 animate-pulse", done: "border-green-500", error: "border-red-500", }; const shouldResize: ShouldResize = useCallback( (event, params) => { if (!wrapperRef.current || !config.contentAware) return true; const contentEl = wrapperRef.current; const paddingX = parseFloat(getComputedStyle(contentEl).paddingLeft) + parseFloat(getComputedStyle(contentEl).paddingRight); const paddingY = parseFloat(getComputedStyle(contentEl).paddingTop) + parseFloat(getComputedStyle(contentEl).paddingBottom); const minW = Math.max( config.minWidth, contentEl.scrollWidth - paddingX + paddingX * 0.5, ); const minH = Math.max( config.minHeight, contentEl.scrollHeight - paddingY + paddingY * 0.5, ); return params.width >= minW && params.height >= minH; }, [config], ); return (
{selected && CORNERS.map((corner) => ( ))} {children} {status === "error" && statusMessage && (
{statusMessage}
)}
); }