|
2 | 2 |
|
3 | 3 | Edges connect nodes together in a flow. This page explains how to define, customize, and interact with edges in Reflex Flow. |
4 | 4 |
|
5 | | -## The `Edge` Type |
| 5 | +## The **Edge** Type |
6 | 6 |
|
7 | 7 | An edge is represented as a Python dictionary with the following fields: |
8 | 8 |
|
@@ -94,3 +94,124 @@ edges: list[Edge] = [ |
94 | 94 | } |
95 | 95 | ] |
96 | 96 | ``` |
| 97 | + |
| 98 | +# Custom Edges |
| 99 | + |
| 100 | +React Flow in Reflex also allows you to define custom edge types. This is useful when you want edges to carry extra functionality (like buttons, labels, or dynamic styling) beyond the default straight or bezier connectors. |
| 101 | + |
| 102 | +```python demo exec |
| 103 | +import reflex as rx |
| 104 | +import reflex_enterprise as rxe |
| 105 | +from reflex_enterprise.components.flow.types import ( |
| 106 | + ConnectionInProgress, |
| 107 | + Edge, |
| 108 | + NoConnection, |
| 109 | + Node, |
| 110 | + Position, |
| 111 | +) |
| 112 | + |
| 113 | +class SimpleEdgeDemoState(rx.State): |
| 114 | + nodes: list[Node] = [ |
| 115 | + {"id": "1", "position": {"x": 0, "y": 0}, "data": {"label": "Node A"}, "style": {"color": "#000000",}}, |
| 116 | + {"id": "2", "position": {"x": 250, "y": 150}, "data": {"label": "Node B"}, "style": {"color": "#000000",}}, |
| 117 | + ] |
| 118 | + edges: list[Edge] = [ |
| 119 | + {"id": "e1-2", "source": "1", "target": "2", "type": "button"} |
| 120 | + ] |
| 121 | + |
| 122 | + @rx.event |
| 123 | + def set_nodes(self, nodes: list[Node]): |
| 124 | + self.nodes = nodes |
| 125 | + |
| 126 | + @rx.event |
| 127 | + def set_edges(self, edges: list[Edge]): |
| 128 | + self.edges = edges |
| 129 | + |
| 130 | + @rx.event |
| 131 | + def handle_connect_end( |
| 132 | + self, |
| 133 | + connection_status: NoConnection | ConnectionInProgress, |
| 134 | + ): |
| 135 | + if not connection_status["isValid"]: |
| 136 | + new_edge = { |
| 137 | + "id": f"{connection_status['fromNode']['id']}-{connection_status['toNode']['id']}", |
| 138 | + "source": connection_status["fromNode"]["id"], |
| 139 | + "target": connection_status["toNode"]["id"], |
| 140 | + "type": "button", |
| 141 | + } |
| 142 | + self.edges.append(new_edge) |
| 143 | + |
| 144 | + |
| 145 | + |
| 146 | +@rx.memo |
| 147 | +def button_edge( |
| 148 | + id: rx.Var[str], |
| 149 | + sourceX: rx.Var[float], |
| 150 | + sourceY: rx.Var[float], |
| 151 | + targetX: rx.Var[float], |
| 152 | + targetY: rx.Var[float], |
| 153 | + sourcePosition: rx.Var[Position], |
| 154 | + targetPosition: rx.Var[Position], |
| 155 | + markerEnd: rx.Var[str], |
| 156 | +): |
| 157 | + bezier_path = rxe.components.flow.util.get_bezier_path( |
| 158 | + source_x=sourceX, |
| 159 | + source_y=sourceY, |
| 160 | + target_x=targetX, |
| 161 | + target_y=targetY, |
| 162 | + source_position=sourcePosition, |
| 163 | + target_position=targetPosition, |
| 164 | + ) |
| 165 | + |
| 166 | + mid_x = bezier_path.label_x |
| 167 | + mid_y = bezier_path.label_y |
| 168 | + |
| 169 | + return rx.fragment( |
| 170 | + rxe.flow.base_edge(path=bezier_path.path, markerEnd=markerEnd), |
| 171 | + rxe.flow.edge_label_renderer( |
| 172 | + rx.el.div( |
| 173 | + rx.el.button( |
| 174 | + "×", |
| 175 | + class_name=("w-[30px] h-[30px] border-2 border-gray-200 bg-gray-200 text-black rounded-full text-[12px] pt-0 cursor-pointer hover:bg-gray-400 hover:text-white"), |
| 176 | + on_click=rx.run_script( |
| 177 | + rxe.flow.api.set_edges( |
| 178 | + rx.vars.FunctionStringVar.create( |
| 179 | + "Array.prototype.filter.call" |
| 180 | + ).call( |
| 181 | + rxe.flow.api.get_edges(), |
| 182 | + rx.Var(f"((edge) => edge.id !== {id})"), |
| 183 | + ), |
| 184 | + ) |
| 185 | + ), |
| 186 | + style={ |
| 187 | + "position": "absolute", |
| 188 | + "left": f"{mid_x}px", |
| 189 | + "top": f"{mid_y}px", |
| 190 | + "transform": "translate(-50%, -50%)", |
| 191 | + "pointerEvents": "all", |
| 192 | + }, |
| 193 | + ), |
| 194 | + ) |
| 195 | + ), |
| 196 | + ) |
| 197 | + |
| 198 | +def very_simple_custom_edge_example(): |
| 199 | + return rx.box( |
| 200 | + rxe.flow( |
| 201 | + rxe.flow.background(), |
| 202 | + default_nodes=SimpleEdgeDemoState.nodes, |
| 203 | + default_edges=SimpleEdgeDemoState.edges, |
| 204 | + nodes=SimpleEdgeDemoState.nodes, |
| 205 | + edges=SimpleEdgeDemoState.edges, |
| 206 | + on_connect=lambda connection: SimpleEdgeDemoState.set_edges( |
| 207 | + rxe.flow.util.add_edge(connection, SimpleEdgeDemoState.edges) |
| 208 | + ), |
| 209 | + on_connect_end=lambda status, event: SimpleEdgeDemoState.handle_connect_end(status), |
| 210 | + edge_types={"button": button_edge}, |
| 211 | + fit_view=True, |
| 212 | + ), |
| 213 | + height="100vh", |
| 214 | + width="100%", |
| 215 | + ) |
| 216 | + |
| 217 | +``` |
0 commit comments