All files / src/pages/VisProgPage/visualProgrammingUI/components NodeComponents.tsx

0% Statements 0/21
0% Branches 0/8
0% Functions 0/9
0% Lines 0/20

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123                                                                                                                                                                                                                                                     
import {NodeToolbar} 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 deleteParentNode = () => {
    deleteNode(nodeId);
  };
 
  const nodeType = nodes.find((node) => node.id === nodeId)?.type as keyof typeof NodeTooltips;
  return (
    <NodeToolbar className={"flex-row align-center"}>
      <button className="Node-toolbar__deletebutton" onClick={deleteParentNode} disabled={!allowDelete}>delete</button>
      <Tooltip nodeType={nodeType}>
        <div className={styles.nodeToolbarTooltip}>i</div>
      </Tooltip>
    </NodeToolbar>);
}
 
 
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 ?
    (<div>
      <div
        onMouseDown={() => {
          updateTooltipPos();
          setShowTooltip(false);
          setDisabled(true);
        }}
        onMouseUp={() => {
          setDisabled(false);
        }}
        onMouseOver={() => {
          if (!disabled) {
            updateTooltipPos();
            setShowTooltip(true);
          }
        }}
        onMouseLeave={ () => setShowTooltip(false)}
      >
        {children}
      </div>
      {showTooltip && createPortal(
        <div
          className={"flex-row"}
          style={{
            pointerEvents: 'none',
            position: 'fixed',
            top: `${coords.top}px`,
            left: `${coords.left}px`,
            transform: 'translateX(-50%)', // Center based on the midpoint
          }}
        >
          <span className={styles.customTooltipHeader}>{nodeType}</span>
          <span className={styles.customTooltip}>
            {NodeTooltips[nodeType] || "Available for drag"}
          </span>
        </div>,
        document.body
      )}
    </div>
  ) : children
}