npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@tisoap/react-flow-smart-edge

v4.0.1

Published

Custom React Flow Edge that never intersects with other nodes

Readme

React Flow Smart Edge

Custom Edges for React Flow that never intersect with other nodes, using pathfinding.

TypeScript Storybook ESLint

Smart Edge

Install

With npm:

npm install @tisoap/react-flow-smart-edge

With yarn:

yarn add @tisoap/react-flow-smart-edge

This package is only compatible with version 12 of React Flow Edge.

Support

Like this project and want to show your support? Buy me a coffee:

ko-fi

Really like this project? Sponsor me on GitHub:

GitHub Sponsors

Usage

This package ships with the following Smart Edges components:

  • SmartBezierEdge: A smart equivalent to React Flow's BezierEdge
  • SmartStraightEdge: A smart equivalent to React Flow's StraightEdge
  • SmartStepEdge: A smart equivalent to React Flow's StepEdge

Each one can be imported individually as a named export.

Example

import React from "react";
import { ReactFlow } from "reactflow";
import { SmartBezierEdge } from "@tisoap/react-flow-smart-edge";
import "@xyflow/react/dist/style.css";

const nodes = [
  {
    id: "1",
    data: { label: "Node 1" },
    position: { x: 300, y: 100 },
  },
  {
    id: "2",
    data: { label: "Node 2" },
    position: { x: 300, y: 200 },
  },
];

const edges = [
  {
    id: "e21",
    source: "2",
    target: "1",
    type: "smart",
  },
];

// You can give any name to your edge types
// https://reactflow.dev/docs/api/edges/custom-edges/
const edgeTypes = {
  smart: SmartBezierEdge,
};

export const Graph = (props) => {
  const { children, ...rest } = props;

  return (
    <ReactFlow
      defaultNodes={nodes}
      defaultEdges={edges}
      edgeTypes={edgeTypes}
      {...rest}
    >
      {children}
    </ReactFlow>
  );
};

Edge Options

All smart edges will take the exact same options as a React Flow Edge.

Custom Smart Edges

You can have more control over how the edge is rerendered by creating a custom edge and using the provided getSmartEdge function. It takes an object with the following keys:

  • sourcePosition, targetPosition, sourceX, sourceY, targetX and targetY: The same values your custom edge will take as props
  • nodes: An array containing all graph nodes, you can get it from the useNodes hook

Example

Just like you can use getBezierPath from reactflow to create a custom edge with a button, you can do the same with getSmartEdge:

import React from "react";
import { useNodes, BezierEdge } from "@xyflow/react";
import { getSmartEdge } from "@tisoap/react-flow-smart-edge";

const foreignObjectSize = 200;

export function SmartEdgeWithButtonLabel(props) {
  const {
    id,
    sourcePosition,
    targetPosition,
    sourceX,
    sourceY,
    targetX,
    targetY,
    style,
    markerStart,
    markerEnd,
  } = props;

  const nodes = useNodes();

  const getSmartEdgeResponse = getSmartEdge({
    sourcePosition,
    targetPosition,
    sourceX,
    sourceY,
    targetX,
    targetY,
    nodes,
  });

  // If the value returned is an Error, it means "getSmartEdge" was unable
  // to find a valid path, and you should do something else instead
  if (smartResponse instanceof Error) {
    return <BezierEdge {...props} />;
  }

  const { edgeCenterX, edgeCenterY, svgPathString } = getSmartEdgeResponse;

  return (
    <>
      <path
        style={style}
        className="react-flow__edge-path"
        d={svgPathString}
        markerEnd={markerEnd}
        markerStart={markerStart}
      />
      <foreignObject
        width={foreignObjectSize}
        height={foreignObjectSize}
        x={edgeCenterX - foreignObjectSize / 2}
        y={edgeCenterY - foreignObjectSize / 2}
        requiredExtensions="http://www.w3.org/1999/xhtml"
      >
        <button
          onClick={(event) => {
            event.stopPropagation();
            alert(`remove ${id}`);
          }}
        >
          X
        </button>
      </foreignObject>
    </>
  );
}

Advanced Custom Smart Edges

The getSmartEdge function also accepts an optional object options, which allows you to configure aspects of the path-finding algorithm. You may use it like so:

const myOptions = {
  // your configuration goes here
  nodePadding: 20,
  gridRatio: 15,
};

// ...

const getSmartEdgeResponse = getSmartEdge({
  sourcePosition,
  targetPosition,
  sourceX,
  sourceY,
  targetX,
  targetY,
  nodes,
  // Pass down options in the getSmartEdge object
  options: myOptions,
});

The options object accepts the following keys (they're all optional):

  • nodePadding: How many pixels of padding are added around nodes, or by how much should the edge avoid the walls of a node. Default 10, minimum 2.
  • gridRatio: The size in pixels of each square grid cell used for path-finding. Smaller values for a more accurate path, bigger for faster path-finding. Default 10, minimum 2.
  • drawEdge: Allows you to change the function responsible to draw the SVG line, by default it's the same used by SmartBezierEdge (more below)
  • generatePath: Allows you to change the function for the path-finding, by default it's the same used by SmartBezierEdge (more below)

drawEdge

With the drawEdge option, you can change the function used to generate the final SVG path string, used to draw the line. By default it's the svgDrawSmoothLinePath function (same as used by the SmartBezierEdge), but the package also includes svgDrawStraightLinePath (same as used by the SmartStraightEdge and SmartStepEdge), or you can provide your own.

import {
  getSmartEdge,
  // Available built-in SVG draw functions
  svgDrawSmoothLinePath,
  svgDrawStraightLinePath,
} from "@tisoap/react-flow-smart-edge";

// Using provided SVG draw functions:
const result = getSmartEdge({
  // ...
  options: {
    drawEdge: svgDrawSmoothLinePath,
  },
});

// ...or using your own custom function
const result = getSmartEdge({
  // ...
  options: {
    drawEdge: (source, target, path) => {
      // your code goes here
      // ...
      return svgPath;
    },
  },
});

The function you provided must comply with this signature:

type SVGDrawFunction = (
  source: XYPosition, // The starting {x, y} point
  target: XYPosition, // The ending  {x, y} point
  path: number[][], // The sequence of points [x, y] the line must follow
) => string; // A string to be used in the "d" property of the SVG line

For inspiration on how to implement your own, you can check the drawSvgPath.ts source code.

generatePath

With the generatePath option, you can change the function used to do Pathfinding. By default, it's the pathfindingAStarDiagonal function (same as used by the SmartBezierEdge), but the package also includes pathfindingAStarNoDiagonal (used by SmartStraightEdge and SmartStepEdge), or your can provide your own.

import {
  getSmartEdge,
  // Available built-in pathfinding functions
  pathfindingAStarDiagonal,
  pathfindingAStarNoDiagonal,
} from "@tisoap/react-flow-smart-edge";

// Using provided pathfinding functions:
const result = getSmartEdge({
  // ...
  options: {
    generatePath: pathfindingAStarDiagonal,
  },
});

// ...or using your own custom function
const result = getSmartEdge({
  // ...
  options: {
    generatePath: (grid, start, end) => {
      // your code goes here
      // ...
      return { fullPath, smoothedPath };
    },
  },
});

The function you provide must comply with this signature:

type PathFindingFunction = (
  grid: Grid, // Grid representation of the graph
  start: XYPosition, // The starting {x, y} point
  end: XYPosition, // The ending  {x, y} point
) => number[][]; // Array of points [x, y] representing the full path with all points

For inspiration on how to implement your own, you can check the generatePath.ts source code.

Advanced Examples

import {
	getSmartEdge,
	svgDrawSmoothLinePath,
	svgDrawStraightLinePath
	pathfindingAStarDiagonal,
	pathfindingAStarNoDiagonal,
} from '@tisoap/react-flow-smart-edge'

// ...

// Same as importing "SmartBezierEdge" directly
const bezierResult = getSmartEdge({
	// ...
	options: {
		drawEdge: svgDrawSmoothLinePath,
		generatePath: pathfindingAStarDiagonal,
	}
})

// Same as importing "SmartStepEdge" directly
const stepResult = getSmartEdge({
	// ...
	options: {
		drawEdge: svgDrawStraightLinePath,
		generatePath: pathfindingAStarNoDiagonal,
	}
})

// Same as importing "SmartStraightEdge" directly
const straightResult = getSmartEdge({
	// ...
	options: {
		drawEdge: svgDrawStraightLinePath,
		generatePath: pathfindingAStarNoDiagonal,
	}
})

Storybook

You can see live Storybook examples by visiting this page, and see their source code here.

License

This project is MIT licensed.