panel-reactflow 0.1.0__tar.gz → 0.2.0rc0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/PKG-INFO +2 -2
  2. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/README.md +1 -1
  3. panel_reactflow-0.2.0rc0/docs/how-to/define-nodes-edges.md +219 -0
  4. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/how-to/embed-views-in-nodes.md +8 -4
  5. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/index.md +5 -1
  6. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/quickstart.md +6 -0
  7. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/pixi.lock +776 -792
  8. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/pyproject.toml +3 -0
  9. panel_reactflow-0.2.0rc0/src/panel_reactflow/base.py +2233 -0
  10. panel_reactflow-0.2.0rc0/src/panel_reactflow/dist/css/reactflow.css +74 -0
  11. panel_reactflow-0.2.0rc0/src/panel_reactflow/dist/icons/gear.svg +1 -0
  12. panel_reactflow-0.2.0rc0/src/panel_reactflow/dist/panel-reactflow.bundle.css +1 -0
  13. panel_reactflow-0.2.0rc0/src/panel_reactflow/dist/panel-reactflow.bundle.js +82 -0
  14. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/src/panel_reactflow/models/reactflow.jsx +33 -76
  15. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/src/panel_reactflow/schema.py +5 -2
  16. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/tests/test_api.py +246 -4
  17. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/tests/ui/test_ui.py +1 -2
  18. panel_reactflow-0.1.0/docs/how-to/define-nodes-edges.md +0 -133
  19. panel_reactflow-0.1.0/src/panel_reactflow/base.py +0 -1016
  20. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/.copier-answers.yml +0 -0
  21. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/.gitattributes +0 -0
  22. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/.github/CODEOWNERS +0 -0
  23. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/.github/dependabot.yml +0 -0
  24. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/.github/workflows/build.yml +0 -0
  25. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/.github/workflows/docs.yml +0 -0
  26. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/.github/workflows/test.yml +0 -0
  27. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/.gitignore +0 -0
  28. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/.pre-commit-config.yaml +0 -0
  29. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/.prettierrc +0 -0
  30. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/LICENSE.txt +0 -0
  31. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/MANIFEST.in +0 -0
  32. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/assets/logo.svg +0 -0
  33. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/assets/screenshots/declare-types.png +0 -0
  34. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/assets/screenshots/define-editors-edge.png +0 -0
  35. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/assets/screenshots/define-editors-node.png +0 -0
  36. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/assets/screenshots/define-nodes-edges.png +0 -0
  37. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/assets/screenshots/embed-views-in-nodes.png +0 -0
  38. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/assets/screenshots/quickstart.png +0 -0
  39. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/assets/screenshots/react-to-events.png +0 -0
  40. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/assets/screenshots/style-nodes-edges.png +0 -0
  41. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/examples.md +0 -0
  42. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/how-to/declare-types.md +0 -0
  43. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/how-to/define-editors.md +0 -0
  44. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/how-to/react-to-events.md +0 -0
  45. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/how-to/style-nodes-edges.md +0 -0
  46. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/reference/panel_reactflow.md +0 -0
  47. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/docs/releases.md +0 -0
  48. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/examples/advanced.py +0 -0
  49. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/examples/custom_editor.py +0 -0
  50. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/examples/edge_editors.py +0 -0
  51. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/examples/schema_types.py +0 -0
  52. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/examples/simple.py +0 -0
  53. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/examples/threejs_viewer.py +0 -0
  54. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/hatch_build.py +0 -0
  55. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/pixi.toml +0 -0
  56. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/src/panel_reactflow/__init__.py +0 -0
  57. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/src/panel_reactflow/__version.py +0 -0
  58. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/src/panel_reactflow/py.typed +0 -0
  59. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/tests/__init__.py +0 -0
  60. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/tests/conftest.py +0 -0
  61. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/tests/test_core.py +0 -0
  62. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/tests/ui/__init__.py +0 -0
  63. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0rc0}/zensical.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: panel-reactflow
3
- Version: 0.1.0
3
+ Version: 0.2.0rc0
4
4
  Summary: A Panel wrapper for the Reactflow JS library.
5
5
  Project-URL: Homepage, https://github.com/panel-extensions/panel-reactflow
6
6
  Project-URL: Source, https://github.com/panel-extensions/panel-reactflow
@@ -80,7 +80,7 @@ import panel as pn
80
80
 
81
81
  from panel_reactflow import ReactFlow
82
82
 
83
- pn.extension()
83
+ pn.extension("jsoneditor")
84
84
 
85
85
  nodes = [
86
86
  {
@@ -37,7 +37,7 @@ import panel as pn
37
37
 
38
38
  from panel_reactflow import ReactFlow
39
39
 
40
- pn.extension()
40
+ pn.extension("jsoneditor")
41
41
 
42
42
  nodes = [
43
43
  {
@@ -0,0 +1,219 @@
1
+ # Define Nodes & Edges
2
+
3
+ Every graph in Panel-ReactFlow is built from two lists: **nodes** and
4
+ **edges**. Nodes represent entities on the canvas; edges represent
5
+ connections between them. Both are plain Python dictionaries, so you can
6
+ construct them from any data source — a database, a config file, or user
7
+ input at runtime.
8
+
9
+ This guide covers how to create nodes and edges, use the helper dataclasses,
10
+ and update data after the graph is live.
11
+
12
+ ![Screenshot: a simple two-node graph with one edge](../assets/screenshots/define-nodes-edges.png)
13
+
14
+ ---
15
+
16
+ ## Define nodes
17
+
18
+ A node dict requires `id`, `position`, and `data`. The display label is a
19
+ **top-level** field — keep it out of `data` so the frontend can render it
20
+ without parsing the payload.
21
+
22
+ ```python
23
+ import panel as pn
24
+
25
+ nodes = [
26
+ {
27
+ "id": "n1",
28
+ "type": "panel",
29
+ "label": "Start",
30
+ "position": {"x": 0, "y": 0},
31
+ "data": {"status": "idle"},
32
+ },
33
+ {
34
+ "id": "n2",
35
+ "type": "panel",
36
+ "label": "End",
37
+ "position": {"x": 260, "y": 60},
38
+ "data": {"status": "done"},
39
+ "view": pn.pane.Markdown("Optional node body"),
40
+ },
41
+ ]
42
+ ```
43
+
44
+ | Key | Required | Description |
45
+ |------------|----------|-------------|
46
+ | `id` | yes | Unique string identifier. |
47
+ | `position` | yes | `{"x": float, "y": float}` canvas coordinates. |
48
+ | `data` | yes | Arbitrary dict of payload data. |
49
+ | `label` | no | Display text shown in the node header. |
50
+ | `type` | no | Node type name (default `"panel"`). |
51
+ | `view` | no | A Panel viewable rendered inside the node. |
52
+
53
+ ---
54
+
55
+ ## Define edges
56
+
57
+ Edges link two nodes by their `id`. Use the top-level `label` for the
58
+ text shown on the edge.
59
+
60
+ ```python
61
+ edges = [
62
+ {"id": "e1", "source": "n1", "target": "n2", "label": "next"},
63
+ ]
64
+ ```
65
+
66
+ | Key | Required | Description |
67
+ |----------------|----------|-------------|
68
+ | `id` | yes | Unique string identifier. |
69
+ | `source` | yes | ID of the source node. |
70
+ | `target` | yes | ID of the target node. |
71
+ | `label` | no | Text rendered on the edge. |
72
+ | `type` | no | Edge type name (for styling / editors). |
73
+ | `data` | no | Arbitrary dict of payload data. |
74
+ | `sourceHandle` | no | Specific output handle on the source node. |
75
+ | `targetHandle` | no | Specific input handle on the target node. |
76
+
77
+ ---
78
+
79
+ ## Use the NodeSpec / EdgeSpec helpers
80
+
81
+ If you prefer a typed API, use the dataclass helpers. They validate fields
82
+ at construction time and are **automatically converted to dictionaries** when
83
+ passed to `ReactFlow`.
84
+
85
+ ```python
86
+ from panel_reactflow import NodeSpec, EdgeSpec, ReactFlow
87
+
88
+ # Create nodes and edges using NodeSpec/EdgeSpec
89
+ nodes = [
90
+ NodeSpec(
91
+ id="n1",
92
+ type="panel",
93
+ label="Start",
94
+ position={"x": 0, "y": 0},
95
+ data={"status": "idle"},
96
+ ),
97
+ NodeSpec(
98
+ id="n2",
99
+ type="panel",
100
+ label="End",
101
+ position={"x": 260, "y": 60},
102
+ data={"status": "done"},
103
+ ),
104
+ ]
105
+
106
+ edges = [
107
+ EdgeSpec(
108
+ id="e1",
109
+ source="n1",
110
+ target="n2",
111
+ label="next",
112
+ ),
113
+ ]
114
+
115
+ # No need to call .to_dict() - automatic serialization!
116
+ flow = ReactFlow(nodes=nodes, edges=edges)
117
+ ```
118
+
119
+ !!! note "Automatic Serialization"
120
+ `NodeSpec` and `EdgeSpec` objects are automatically converted to dictionaries
121
+ when passed to `ReactFlow`. You don't need to call `.to_dict()` manually.
122
+
123
+ However, `.to_dict()` is still available if you need to convert them explicitly
124
+ for other use cases:
125
+
126
+ ```python
127
+ node_dict = NodeSpec(id="n1", position={"x": 0, "y": 0}).to_dict()
128
+ ```
129
+
130
+ ---
131
+
132
+ ## Connect to specific handles
133
+
134
+ When a node type defines multiple input or output handles (via `inputs=["a", "b"]` or `outputs=["x", "y"]`), you can route edges to specific handles using `sourceHandle` and `targetHandle`.
135
+
136
+ ```python
137
+ from panel_reactflow import ReactFlow, NodeSpec, EdgeSpec, NodeType
138
+
139
+ # Define node types with multiple handles
140
+ node_types = {
141
+ "producer": NodeType(
142
+ type="producer",
143
+ label="Producer",
144
+ inputs=[],
145
+ outputs=["result", "error"]
146
+ ),
147
+ "consumer": NodeType(
148
+ type="consumer",
149
+ label="Consumer",
150
+ inputs=["data", "config"],
151
+ outputs=[]
152
+ ),
153
+ }
154
+
155
+ # Create nodes
156
+ nodes = [
157
+ NodeSpec(id="p", type="producer", position={"x": 0, "y": 0}, label="Producer").to_dict(),
158
+ NodeSpec(id="c", type="consumer", position={"x": 400, "y": 0}, label="Consumer").to_dict(),
159
+ ]
160
+
161
+ # Connect producer's "result" output to consumer's "data" input
162
+ edges = [
163
+ EdgeSpec(
164
+ id="e1",
165
+ source="p",
166
+ target="c",
167
+ sourceHandle="result",
168
+ targetHandle="data"
169
+ ).to_dict(),
170
+ ]
171
+
172
+ flow = ReactFlow(nodes=nodes, edges=edges, node_types=node_types)
173
+ ```
174
+
175
+ Without `sourceHandle` and `targetHandle`, edges connect to the default (first) handle on each node.
176
+
177
+ ---
178
+
179
+ ## Update data vs. label
180
+
181
+ `data` and `label` live in different places and are updated differently:
182
+
183
+ - **Data** — use `patch_node_data()` or `patch_edge_data()`. This sends
184
+ an incremental patch to the frontend without replacing the full list.
185
+ - **Label** — replace the node/edge in `flow.nodes` or `flow.edges`.
186
+
187
+ ```python
188
+ # Patch a data field
189
+ flow.patch_node_data("n1", {"status": "running"})
190
+ flow.patch_edge_data("e1", {"weight": 0.75})
191
+
192
+ # Update a label
193
+ flow.nodes = [
194
+ {**node, "label": "Start (running)"} if node["id"] == "n1" else node
195
+ for node in flow.nodes
196
+ ]
197
+ ```
198
+
199
+ ---
200
+
201
+ ## Add and remove at runtime
202
+
203
+ You can use either plain dictionaries or `NodeSpec`/`EdgeSpec` objects with the
204
+ `add_node()` and `add_edge()` methods:
205
+
206
+ ```python
207
+ # Using plain dictionaries
208
+ flow.add_node({"id": "n3", "position": {"x": 520, "y": 0}, "label": "New", "data": {}})
209
+ flow.add_edge({"source": "n2", "target": "n3", "data": {}})
210
+
211
+ # Or using NodeSpec/EdgeSpec (no .to_dict() needed)
212
+ from panel_reactflow import NodeSpec, EdgeSpec
213
+
214
+ flow.add_node(NodeSpec(id="n4", position={"x": 780, "y": 0}, label="Another"))
215
+ flow.add_edge(EdgeSpec(id="e2", source="n3", target="n4"))
216
+
217
+ flow.remove_node("n3") # also removes connected edges
218
+ flow.remove_edge("e1")
219
+ ```
@@ -50,13 +50,17 @@ flow = ReactFlow(nodes=nodes, edges=[], sizing_mode="stretch_both")
50
50
 
51
51
  ## Add a view when adding a node at runtime
52
52
 
53
- `add_node()` accepts an optional `view` keyword argument:
53
+ Pass a `NodeSpec` with a `view` to `add_node()`:
54
54
 
55
55
  ```python
56
- flow.add_node(
57
- {"id": "live", "label": "Live Feed", "position": {"x": 600, "y": 0}, "data": {}},
56
+ from panel_reactflow import NodeSpec
57
+
58
+ flow.add_node(NodeSpec(
59
+ id="live",
60
+ label="Live Feed",
61
+ position={"x": 600, "y": 0},
58
62
  view=pn.indicators.Number(value=42, name="Metric"),
59
- )
63
+ ))
60
64
  ```
61
65
 
62
66
  ---
@@ -22,11 +22,15 @@ generate forms, and plug in editors where you need full control.
22
22
 
23
23
  ## Quickstart
24
24
 
25
+ !!! tip "JSONEditor Extension Required"
26
+ ReactFlow requires the `jsoneditor` Panel extension for editing node and edge data.
27
+ Always call `pn.extension("jsoneditor")` at the start of your application.
28
+
25
29
  ```python
26
30
  import panel as pn
27
31
  from panel_reactflow import NodeType, ReactFlow
28
32
 
29
- pn.extension()
33
+ pn.extension("jsoneditor")
30
34
 
31
35
  task_schema = {
32
36
  "type": "object",
@@ -14,6 +14,12 @@ pip install panel-reactflow
14
14
 
15
15
  ## Minimal app
16
16
 
17
+ !!! note "Required Extension"
18
+ ReactFlow uses Panel's JSONEditor widget for editing node and edge data.
19
+ You must call `pn.extension("jsoneditor")` before creating ReactFlow instances
20
+ to ensure the extension loads correctly. This should be done early in your
21
+ application, typically right after your imports.
22
+
17
23
  ```python
18
24
  import panel as pn
19
25