UNPKG

@unblocks/xyflow-react

Version:
240 lines (231 loc) 8.64 kB
'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 }; var DEFAULT_CHILDREN = /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Background, null), /* @__PURE__ */ React.createElement(Controls, null)); function DagreFlow(_a) { var _b = _a, { graph, dagreOptions, children } = _b, restProps = __objRest(_b, ["graph", "dagreOptions", "children"]); 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), typeof children === "undefined" ? DEFAULT_CHILDREN : children); } // 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 };