Spaces:
Running
Running
File size: 4,990 Bytes
1270bff 0233bb7 0d8f49d 0233bb7 7fda361 7ed5764 0d8f49d 0233bb7 1e30a56 0233bb7 0d8f49d f0ea27c 7fda361 483664b 7fda361 d57c7f6 7fda361 7ed5764 7fda361 d57c7f6 7ed5764 7fda361 d57c7f6 7ed5764 7fda361 964d1be 7fda361 7ed5764 7fda361 9736182 4e79985 9736182 4e79985 9736182 4e79985 9736182 0d8f49d 483664b 7fda361 483664b d57c7f6 483664b 7ed5764 9736182 22718a7 9736182 7fda361 7ed5764 8ec0e19 7ed5764 7fda361 9736182 f0ea27c 0233bb7 f0ea27c 0233bb7 f0ea27c 0233bb7 f0ea27c 0233bb7 f0ea27c 0233bb7 f0ea27c 7fda361 7ed5764 0d8f49d 4837736 0d8f49d 6629baa 0d8f49d 7ed5764 d983a3c 9736182 7ed5764 1270bff 7ed5764 1270bff 7ed5764 d983a3c 7fda361 0d8f49d |
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 158 159 160 161 162 163 |
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";
interface LynxKiteNodeProps {
id: string;
width: number;
height: number;
nodeStyle: any;
data: any;
children: any;
}
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;
}
const OP_COLORS: { [key: string]: string } = {
pink: "oklch(75% 0.2 0)",
orange: "oklch(75% 0.2 55)",
green: "oklch(75% 0.2 150)",
blue: "oklch(75% 0.2 230)",
purple: "oklch(75% 0.2 290)",
};
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 = OP_COLORS[data.meta.value.color] || data.meta.value.color;
}
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}`}
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>
);
};
}
|