Spaces:
Running
Running
File size: 3,304 Bytes
7ed5764 7fda361 7ed5764 7fda361 483664b 7fda361 483664b 7fda361 7ed5764 7fda361 7ed5764 7fda361 7ed5764 7fda361 7ed5764 7fda361 483664b 7fda361 483664b 7fda361 483664b 7ed5764 7fda361 7ed5764 8ec0e19 7ed5764 7fda361 4f7c2bb 8023f1f 4f7c2bb 7fda361 7ed5764 d983a3c 7ed5764 d983a3c 7fda361 |
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 |
import {
Handle,
NodeResizeControl,
type Position,
useReactFlow,
} from "@xyflow/react";
// @ts-ignore
import ChevronDownRight from "~icons/tabler/chevron-down-right.jsx";
interface LynxKiteNodeProps {
id: string;
width: number;
height: number;
nodeStyle: any;
data: any;
children: any;
}
function getHandles(inputs: object, outputs: object) {
const handles: {
position: "top" | "bottom" | "left" | "right";
name: string;
index: number;
offsetPercentage: number;
showLabel: boolean;
type: "source" | "target";
}[] = [];
for (const e of Object.values(inputs)) {
handles.push({ ...e, type: "target" });
}
for (const e of Object.values(outputs)) {
handles.push({ ...e, type: "source" });
}
const counts = { top: 0, bottom: 0, left: 0, right: 0 };
for (const e of handles) {
e.index = counts[e.position];
counts[e.position]++;
}
for (const e of handles) {
e.offsetPercentage = (100 * (e.index + 1)) / (counts[e.position] + 1);
const simpleHorizontal =
counts.top === 0 && counts.bottom === 0 && handles.length <= 2;
const simpleVertical =
counts.left === 0 && counts.right === 0 && handles.length <= 2;
e.showLabel = !simpleHorizontal && !simpleVertical;
}
return handles;
}
export default function LynxKiteNode(props: LynxKiteNodeProps) {
const reactFlow = useReactFlow();
const data = props.data;
const expanded = !data.collapsed;
const handles = getHandles(data.meta?.inputs || {}, data.meta?.outputs || {});
function titleClicked() {
reactFlow.updateNodeData(props.id, { collapsed: expanded });
}
const handleOffsetDirection = {
top: "left",
bottom: "left",
left: "top",
right: "top",
};
return (
<div
className={`node-container ${expanded ? "expanded" : "collapsed"} `}
style={{
width: props.width || 200,
height: expanded ? props.height || 200 : undefined,
}}
>
<div className="lynxkite-node" style={props.nodeStyle}>
<div
className={`title bg-primary ${data.status}`}
onClick={titleClicked}
>
{data.title}
{data.error && <span className="title-icon">⚠️</span>}
{expanded || <span className="title-icon">⋯</span>}
</div>
{expanded && (
<>
{data.error && <div className="error">{data.error}</div>}
{props.children}
<NodeResizeControl
minWidth={100}
minHeight={50}
style={{ background: "transparent", border: "none" }}
>
<ChevronDownRight className="node-resizer" />
</NodeResizeControl>
</>
)}
{handles.map((handle) => (
<Handle
key={handle.name}
id={handle.name}
type={handle.type}
position={handle.position as Position}
style={{
[handleOffsetDirection[handle.position]]:
`${handle.offsetPercentage}% `,
}}
>
{handle.showLabel && (
<span className="handle-name">
{handle.name.replace(/_/g, " ")}
</span>
)}
</Handle>
))}
</div>
</div>
);
}
|