// This program has been developed by students from the bachelor Computer Science at Utrecht // University within the Software Project course. // © Copyright Utrecht University (Department of Information and Computing Sciences) import {NodeToolbar, useReactFlow} from '@xyflow/react'; import '@xyflow/react/dist/style.css'; import {type JSX, useState} from "react"; import {createPortal} from "react-dom"; import styles from "../../VisProg.module.css"; import {NodeTooltips} from "../NodeRegistry.ts"; import useFlowStore from "../VisProgStores.tsx"; /** * Props for the Toolbar component. * * @property nodeId - The ID of the node this toolbar is attached to. * @property allowDelete - If `true`, the delete button is enabled; otherwise disabled. */ type ToolbarProps = { nodeId: string; allowDelete: boolean; }; /** * Node Toolbar definition: * Handles: node deleting functionality * Can be integrated to any custom node component as a React component * * @param {string} nodeId - The ID of the node for which the toolbar is rendered. * @param {boolean} allowDelete - Enables or disables the delete functionality. * @returns {React.JSX.Element} A JSX element representing the toolbar. * @constructor */ export function Toolbar({nodeId, allowDelete}: ToolbarProps) { const {nodes, deleteNode} = useFlowStore(); const { deleteElements } = useReactFlow(); const deleteParentNode = () => { deleteNode(nodeId, deleteElements); }; const nodeType = nodes.find((node) => node.id === nodeId)?.type as keyof typeof NodeTooltips; return (
i
); } type TooltipProps = { nodeType?: keyof typeof NodeTooltips; children: JSX.Element; }; /** * A general tooltip component, that can be used as a wrapper for any component * that has a nodeType and a corresponding nodeTooltip. * * currently used to show tooltips for draggable-nodes and nodes inside the editor * * @param {"start" | "end" | "phase" | "norm" | "goal" | "trigger" | "basic_belief" | undefined} nodeType * @param {React.JSX.Element} children * @returns {React.JSX.Element} * @constructor */ export function Tooltip({ nodeType, children }: TooltipProps) { const [showTooltip, setShowTooltip] = useState(false); const [disabled , setDisabled] = useState(false); const [coords, setCoords] = useState({ top: 0, left: 0 }); const updateTooltipPos = () => { const rect = document.getElementById("draggable-sidebar")!.getBoundingClientRect(); setCoords({ // Position exactly below the bottom edge of the draggable sidebar (plus a small gap) top: rect.bottom + 10, left: rect.left + rect.width / 2, // Keep it horizontally centered }); }; return nodeType ? (
{ updateTooltipPos(); setShowTooltip(false); setDisabled(true); }} onMouseUp={() => { setDisabled(false); }} onMouseOver={() => { if (!disabled) { updateTooltipPos(); setShowTooltip(true); } }} onMouseLeave={ () => setShowTooltip(false)} > {children}
{showTooltip && createPortal(
{nodeType} {NodeTooltips[nodeType] || "Available for drag"}
, document.body )}
) : children }