Spaces:
Running
Running
File size: 4,894 Bytes
a112474 16682aa cedd3c4 16682aa 98f8f03 d460634 cedd3c4 16682aa dfaccc7 16682aa cedd3c4 d7943fc 91961e7 98f8f03 dfd9216 98f8f03 91961e7 98f8f03 114fd1c 98f8f03 d460634 98f8f03 114fd1c d460634 98f8f03 114fd1c d460634 98f8f03 1ca8050 98f8f03 d460634 98f8f03 cedd3c4 dfd9216 98f8f03 dfd9216 114fd1c dfd9216 d460634 454a221 6565904 91961e7 454a221 98f8f03 d460634 ef8a15c d460634 98f8f03 454a221 502f722 454a221 d7943fc 16682aa d7943fc 16682aa d7943fc 16682aa d7943fc 16682aa d7943fc 16682aa d7943fc 98f8f03 d460634 cedd3c4 44b2aaf cedd3c4 fd3b7ca cedd3c4 d460634 f366c41 454a221 d460634 a112474 d460634 a112474 d460634 f366c41 98f8f03 cedd3c4 |
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 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
import { Handle, NodeResizeControl, type Position, useReactFlow } from "@xyflow/react";
import type React from "react";
import { ErrorBoundary } from "react-error-boundary";
// @ts-ignore
import AlertTriangle from "~icons/tabler/alert-triangle-filled.jsx";
// @ts-ignore
import ChevronDownRight from "~icons/tabler/chevron-down-right.jsx";
// @ts-ignore
import Dots from "~icons/tabler/dots.jsx";
// @ts-ignore
import Help from "~icons/tabler/question-mark.jsx";
// @ts-ignore
import Skull from "~icons/tabler/skull.jsx";
import Tooltip from "../../Tooltip";
import { COLORS } from "../../common.ts";
interface LynxKiteNodeProps {
id: string;
width: number;
height: number;
nodeStyle: any;
data: any;
children: any;
parentId?: string;
}
function getHandles(inputs: any[], outputs: any[]) {
const handles: {
position: "top" | "bottom" | "left" | "right";
name: string;
index: number;
offsetPercentage: number;
showLabel: boolean;
type: "source" | "target";
}[] = [];
for (const e of inputs) {
handles.push({ ...e, type: "target" });
}
for (const e of 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]++;
}
const simpleHorizontal =
counts.top === 0 && counts.bottom === 0 && counts.left <= 1 && counts.right <= 1;
const simpleVertical =
counts.left === 0 && counts.right === 0 && counts.top <= 1 && counts.bottom <= 1;
for (const e of handles) {
e.offsetPercentage = (100 * (e.index + 1)) / (counts[e.position] + 1);
e.showLabel = !simpleHorizontal && !simpleVertical;
}
return handles;
}
function LynxKiteNodeComponent(props: LynxKiteNodeProps) {
const reactFlow = useReactFlow();
const data = props.data;
const expanded = !data.collapsed;
const handles = getHandles(data.meta?.value?.inputs || [], data.meta?.value?.outputs || []);
function titleClicked() {
reactFlow.updateNodeData(props.id, { collapsed: expanded });
}
const handleOffsetDirection = {
top: "left",
bottom: "left",
left: "top",
right: "top",
};
const titleStyle: { backgroundColor?: string } = {};
if (data.meta?.value?.color) {
titleStyle.backgroundColor = COLORS[data.meta.value.color] || data.meta.value.color;
}
return (
<div
className={`node-container ${expanded ? "expanded" : "collapsed"} ${props.parentId ? "in-group" : ""}`}
style={{
width: props.width || 200,
height: expanded ? props.height || 200 : undefined,
}}
>
<div className="lynxkite-node" style={props.nodeStyle}>
<div
className={`title bg-primary drag-handle ${data.status}`}
style={titleStyle}
onClick={titleClicked}
>
<span className="title-title">{data.title}</span>
{data.error && (
<Tooltip doc={`Error: ${data.error}`}>
<AlertTriangle />
</Tooltip>
)}
{expanded || (
<Tooltip doc="Click to expand node">
<Dots />
</Tooltip>
)}
<Tooltip doc={data.meta?.value?.doc}>
<Help />
</Tooltip>
</div>
{expanded && (
<>
{data.error && <div className="error">{data.error}</div>}
<ErrorBoundary
resetKeys={[props]}
fallback={
<p className="error" style={{ display: "flex", alignItems: "center", gap: 8 }}>
<Skull style={{ fontSize: 20 }} />
Failed to display this node.
</p>
}
>
<div className="node-content">{props.children}</div>
</ErrorBoundary>
<NodeResizeControl
minWidth={100}
minHeight={50}
style={{ background: "transparent", border: "none" }}
>
<ChevronDownRight className="node-resizer" />
</NodeResizeControl>
</>
)}
{handles.map((handle) => (
<Handle
key={`${handle.name} on ${handle.position}`}
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>
);
}
export default function LynxKiteNode(Component: React.ComponentType<any>) {
return (props: any) => {
return (
<LynxKiteNodeComponent {...props}>
<Component {...props} />
</LynxKiteNodeComponent>
);
};
}
|