@unblocks/xyflow-react
Version:
Utilities for working with @xyflow/react
239 lines (230 loc) • 8.47 kB
JavaScript
'use client'
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __objRest = (source, exclude) => {
var target = {};
for (var prop in source)
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
target[prop] = source[prop];
if (source != null && __getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(source)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
target[prop] = source[prop];
}
return target;
};
// src/components/DagreFlow.tsx
import React, { useEffect, useMemo, useRef, useState } from "react";
import { Background, Controls, ReactFlow, useNodesInitialized, useNodesState, useReactFlow } from "@xyflow/react";
// src/models/dagreLayout.ts
import Dagre from "@dagrejs/dagre";
var DEFAULT_DAGRE_OPTIONS = { direction: "LR", nodesep: 8, ranksep: 48 };
function dagreLayout(nodes, edges, options = DEFAULT_DAGRE_OPTIONS) {
const g = new Dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({}));
const { nodesep = 8, ranksep = 48 } = options;
g.setGraph({ rankdir: options.direction, nodesep, ranksep });
edges.forEach((edge) => g.setEdge(edge.source, edge.target));
nodes.forEach(
(node) => {
var _a, _b, _c, _d;
return g.setNode(node.id, __spreadProps(__spreadValues({}, node), {
width: (_b = (_a = node.measured) == null ? void 0 : _a.width) != null ? _b : 0,
height: (_d = (_c = node.measured) == null ? void 0 : _c.height) != null ? _d : 0
}));
}
);
Dagre.layout(g);
return {
nodes: nodes.map((node) => {
var _a, _b, _c, _d;
const position = g.node(node.id);
const x = position.x - ((_b = (_a = node.measured) == null ? void 0 : _a.width) != null ? _b : 0) / 2;
const y = position.y - ((_d = (_c = node.measured) == null ? void 0 : _c.height) != null ? _d : 0) / 2;
return __spreadProps(__spreadValues({}, node), { position: { x, y } });
}),
edges
};
}
// src/components/DagreFlow.tsx
var OPTIONS = {
includeHiddenNodes: false
};
function DagreFlow(_a) {
var _b = _a, { graph, dagreOptions } = _b, restProps = __objRest(_b, ["graph", "dagreOptions"]);
const nodesInitialized = useNodesInitialized(OPTIONS);
const { fitView } = useReactFlow();
const [nodes, setNodes, onNodesChange] = useNodesState(graph.nodes);
const [layoutedNodes, setLayoutedNodes] = useState(graph.nodes);
const isInitialized = useRef(false);
useEffect(() => {
setLayoutedNodes(graph.nodes);
setNodes(graph.nodes);
}, [graph, setNodes]);
useEffect(() => {
if (nodesInitialized) {
if (!isInitialized.current) {
const newNodes = dagreLayout(nodes, graph.edges, dagreOptions).nodes;
setLayoutedNodes(newNodes.concat());
isInitialized.current = true;
}
} else {
setLayoutedNodes(nodes.concat());
isInitialized.current = false;
}
setTimeout(() => {
requestAnimationFrame(() => {
fitView();
});
}, 10);
}, [nodes, fitView, graph, nodesInitialized, dagreOptions]);
const allEdges = useMemo(() => graph.getAllEdges(), [graph]);
return /* @__PURE__ */ React.createElement(ReactFlow, __spreadValues({ nodes: layoutedNodes, edges: allEdges, onNodesChange, fitView: true }, restProps), /* @__PURE__ */ React.createElement(Background, null), /* @__PURE__ */ React.createElement(Controls, null));
}
// src/components/MultiHandle.tsx
import React2, { memo } from "react";
import { Handle, Position } from "@xyflow/react";
function MultiHandle({
topSourceHandle = false,
topTargetHandle = true,
leftSourceHandle = false,
leftTargetHandle = false,
rightSourceHandle = false,
rightTargetHandle = false,
bottomSourceHandle = true,
bottomTargetHandle = false
}) {
return /* @__PURE__ */ React2.createElement(React2.Fragment, null, topSourceHandle && /* @__PURE__ */ React2.createElement(Handle, { type: "source", id: "top-source", position: Position.Top }), topTargetHandle && /* @__PURE__ */ React2.createElement(Handle, { type: "target", id: "top-target", position: Position.Top }), bottomSourceHandle && /* @__PURE__ */ React2.createElement(Handle, { type: "source", id: "bottom-source", position: Position.Bottom }), bottomTargetHandle && /* @__PURE__ */ React2.createElement(Handle, { type: "target", id: "bottom-target", position: Position.Bottom }), leftSourceHandle && /* @__PURE__ */ React2.createElement(Handle, { type: "source", id: "left-source", position: Position.Left }), leftTargetHandle && /* @__PURE__ */ React2.createElement(Handle, { type: "target", id: "left-target", position: Position.Left }), rightSourceHandle && /* @__PURE__ */ React2.createElement(Handle, { type: "source", id: "right-source", position: Position.Right }), rightTargetHandle && /* @__PURE__ */ React2.createElement(Handle, { type: "target", id: "right-target", position: Position.Right }));
}
var MultiHandle_default = memo(MultiHandle);
// src/components/WithMultiHandle.tsx
import React3, { memo as memo2 } from "react";
function WithMultiHandle(_a) {
var _b = _a, { children } = _b, restProps = __objRest(_b, ["children"]);
return /* @__PURE__ */ React3.createElement(React3.Fragment, null, children, /* @__PURE__ */ React3.createElement(MultiHandle_default, __spreadValues({}, restProps)));
}
var WithMultiHandle_default = memo2(WithMultiHandle);
// src/models/Graph.ts
var Graph = class {
constructor() {
this.nodes = [];
this.edges = [];
this.extraEdges = [];
this.nodeLookup = {};
this.edgeLookup = {};
this.extraEdgeLookup = {};
}
addNode(node) {
if (this.nodeLookup[node.id]) {
return this;
}
this.nodes.push(node);
this.nodeLookup[node.id] = node;
return this;
}
addNodes(nodes) {
nodes.forEach((node) => this.addNode(node));
return this;
}
findNode(id) {
return this.nodeLookup[id];
}
/**
* Add an edge to the graph (affects the layout)
* @param edge
*/
addEdge(edge) {
if (this.edgeLookup[edge.id]) {
return;
}
this.edges.push(edge);
this.edgeLookup[edge.id] = edge;
return this;
}
addEdges(edges) {
edges.forEach((edge) => this.addEdge(edge));
return this;
}
/**
* Add an extra edge that does not affect the layout
* @param edge edge
*/
addExtraEdge(edge) {
if (this.extraEdgeLookup[edge.id]) {
return this;
}
this.extraEdges.push(edge);
this.extraEdgeLookup[edge.id] = edge;
return this;
}
addExtraEdges(edges) {
edges.forEach((edge) => this.addExtraEdge(edge));
return this;
}
findEdge(id) {
return this.edgeLookup[id];
}
getAllEdges() {
return this.edges.concat(this.extraEdges);
}
};
// src/models/createNode.ts
import { Position as Position2 } from "@xyflow/react";
function createNode(_a) {
var _b = _a, {
id,
data,
draggable = false,
position,
sourcePosition = Position2.Bottom,
targetPosition = Position2.Top
} = _b, rest = __objRest(_b, [
"id",
"data",
"draggable",
"position",
"sourcePosition",
"targetPosition"
]);
return __spreadValues({
id,
data,
draggable,
position: typeof position === "undefined" ? { x: 0, y: 0 } : position,
sourcePosition,
targetPosition
}, rest);
}
// src/models/createEdge.ts
function createEdge(_a) {
var _b = _a, { id, source, target } = _b, rest = __objRest(_b, ["id", "source", "target"]);
return __spreadValues({
id: id != null ? id : `${source}-${target}`,
source,
target
}, rest);
}
export {
DagreFlow,
Graph,
MultiHandle_default as MultiHandle,
WithMultiHandle_default as WithMultiHandle,
createEdge,
createNode
};