panel-reactflow 0.1.0__tar.gz → 0.2.0__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.0}/.github/workflows/test.yml +1 -0
  2. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/PKG-INFO +2 -2
  3. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/README.md +1 -1
  4. panel_reactflow-0.2.0/docs/how-to/define-nodes-edges.md +219 -0
  5. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/docs/how-to/embed-views-in-nodes.md +8 -4
  6. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/docs/index.md +5 -1
  7. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/docs/quickstart.md +6 -0
  8. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/docs/releases.md +27 -0
  9. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/pixi.lock +776 -792
  10. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/pyproject.toml +3 -0
  11. panel_reactflow-0.2.0/src/panel_reactflow/base.py +2232 -0
  12. panel_reactflow-0.2.0/src/panel_reactflow/dist/css/reactflow.css +74 -0
  13. panel_reactflow-0.2.0/src/panel_reactflow/dist/icons/gear.svg +1 -0
  14. panel_reactflow-0.2.0/src/panel_reactflow/dist/panel-reactflow.bundle.css +1 -0
  15. panel_reactflow-0.2.0/src/panel_reactflow/dist/panel-reactflow.bundle.js +82 -0
  16. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/src/panel_reactflow/models/reactflow.jsx +33 -76
  17. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/src/panel_reactflow/schema.py +5 -2
  18. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/tests/test_api.py +246 -4
  19. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/tests/ui/test_ui.py +5 -9
  20. panel_reactflow-0.1.0/docs/how-to/define-nodes-edges.md +0 -133
  21. panel_reactflow-0.1.0/src/panel_reactflow/base.py +0 -1016
  22. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/.copier-answers.yml +0 -0
  23. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/.gitattributes +0 -0
  24. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/.github/CODEOWNERS +0 -0
  25. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/.github/dependabot.yml +0 -0
  26. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/.github/workflows/build.yml +0 -0
  27. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/.github/workflows/docs.yml +0 -0
  28. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/.gitignore +0 -0
  29. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/.pre-commit-config.yaml +0 -0
  30. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/.prettierrc +0 -0
  31. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/LICENSE.txt +0 -0
  32. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/MANIFEST.in +0 -0
  33. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/docs/assets/logo.svg +0 -0
  34. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/docs/assets/screenshots/declare-types.png +0 -0
  35. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/docs/assets/screenshots/define-editors-edge.png +0 -0
  36. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/docs/assets/screenshots/define-editors-node.png +0 -0
  37. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/docs/assets/screenshots/define-nodes-edges.png +0 -0
  38. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/docs/assets/screenshots/embed-views-in-nodes.png +0 -0
  39. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/docs/assets/screenshots/quickstart.png +0 -0
  40. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/docs/assets/screenshots/react-to-events.png +0 -0
  41. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/docs/assets/screenshots/style-nodes-edges.png +0 -0
  42. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/docs/examples.md +0 -0
  43. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/docs/how-to/declare-types.md +0 -0
  44. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/docs/how-to/define-editors.md +0 -0
  45. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/docs/how-to/react-to-events.md +0 -0
  46. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/docs/how-to/style-nodes-edges.md +0 -0
  47. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/docs/reference/panel_reactflow.md +0 -0
  48. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/examples/advanced.py +0 -0
  49. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/examples/custom_editor.py +0 -0
  50. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/examples/edge_editors.py +0 -0
  51. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/examples/schema_types.py +0 -0
  52. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/examples/simple.py +0 -0
  53. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/examples/threejs_viewer.py +0 -0
  54. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/hatch_build.py +0 -0
  55. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/pixi.toml +0 -0
  56. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/src/panel_reactflow/__init__.py +0 -0
  57. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/src/panel_reactflow/__version.py +0 -0
  58. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/src/panel_reactflow/py.typed +0 -0
  59. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/tests/__init__.py +0 -0
  60. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/tests/conftest.py +0 -0
  61. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/tests/test_core.py +0 -0
  62. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/tests/ui/__init__.py +0 -0
  63. {panel_reactflow-0.1.0 → panel_reactflow-0.2.0}/zensical.toml +0 -0
@@ -135,6 +135,7 @@ jobs:
135
135
  environment: ["test-ui"]
136
136
  timeout-minutes: 60
137
137
  env:
138
+ PYTHONIOENCODING: utf8
138
139
  PANEL_LOG_LEVEL: info
139
140
  FAIL: "--screenshot only-on-failure --full-page-screenshot --output ui_screenshots --tracing retain-on-failure"
140
141
  steps:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: panel-reactflow
3
- Version: 0.1.0
3
+ Version: 0.2.0
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
 
@@ -1,5 +1,32 @@
1
1
  # Release Notes
2
2
 
3
+ ## Version 0.2.0
4
+
5
+ This release focuses on stronger typed graph specs, better node-view handling,
6
+ and improved docs and packaging.
7
+
8
+ ### Highlights
9
+
10
+ - **`NodeSpec` view support** — added a `view` parameter to `NodeSpec` and
11
+ fixed `add_node` behavior so embedded views are preserved when adding nodes
12
+ programmatically.
13
+ - **Safer embedded view handling** — fixed an `AttributeError` when node views
14
+ are Panel `Viewer` objects or other arbitrary view-like objects.
15
+ - **`EdgeSpec` handle targeting** — added `sourceHandle` and `targetHandle`
16
+ fields to support explicit edge-to-port connections.
17
+ - **Spec auto-serialization** — added automatic serialization for `NodeSpec`
18
+ and `EdgeSpec` objects to reduce boilerplate when using dataclass-based graph
19
+ definitions.
20
+ - **Handle rendering fix** — corrected empty handle list behavior so `[]` is
21
+ treated distinctly from missing/undefined handles.
22
+ - **Styling hook for labels** — added the `rf-node-label` CSS class on node
23
+ labels for easier targeted styling.
24
+ - **Docs and onboarding updates** — quickstart and index docs now explicitly
25
+ document the required `pn.extension("jsoneditor")` setup; additional how-to
26
+ docs were updated for new handle and serialization behavior.
27
+ - **Packaging reliability** — ensured the frontend `dist` assets are included
28
+ in distributions.
29
+
3
30
  ## Version 0.1.0
4
31
 
5
32
  *Initial release*