panel-reactflow 0.0.1a1__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 (66) hide show
  1. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/.github/workflows/docs.yml +19 -2
  2. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/PKG-INFO +8 -4
  3. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/README.md +7 -3
  4. panel_reactflow-0.2.0rc0/docs/assets/screenshots/declare-types.png +0 -0
  5. panel_reactflow-0.2.0rc0/docs/assets/screenshots/define-editors-edge.png +0 -0
  6. panel_reactflow-0.2.0rc0/docs/assets/screenshots/define-editors-node.png +0 -0
  7. panel_reactflow-0.2.0rc0/docs/assets/screenshots/define-nodes-edges.png +0 -0
  8. panel_reactflow-0.2.0rc0/docs/assets/screenshots/embed-views-in-nodes.png +0 -0
  9. panel_reactflow-0.2.0rc0/docs/assets/screenshots/quickstart.png +0 -0
  10. panel_reactflow-0.2.0rc0/docs/assets/screenshots/react-to-events.png +0 -0
  11. panel_reactflow-0.2.0rc0/docs/assets/screenshots/style-nodes-edges.png +0 -0
  12. panel_reactflow-0.2.0rc0/docs/how-to/declare-types.md +125 -0
  13. panel_reactflow-0.2.0rc0/docs/how-to/define-editors.md +239 -0
  14. panel_reactflow-0.2.0rc0/docs/how-to/define-nodes-edges.md +219 -0
  15. panel_reactflow-0.2.0rc0/docs/how-to/embed-views-in-nodes.md +118 -0
  16. panel_reactflow-0.2.0rc0/docs/how-to/react-to-events.md +115 -0
  17. panel_reactflow-0.2.0rc0/docs/how-to/style-nodes-edges.md +149 -0
  18. panel_reactflow-0.2.0rc0/docs/index.md +72 -0
  19. panel_reactflow-0.2.0rc0/docs/quickstart.md +71 -0
  20. panel_reactflow-0.2.0rc0/docs/releases.md +42 -0
  21. panel_reactflow-0.2.0rc0/examples/advanced.py +124 -0
  22. panel_reactflow-0.2.0rc0/examples/custom_editor.py +87 -0
  23. panel_reactflow-0.2.0rc0/examples/edge_editors.py +118 -0
  24. panel_reactflow-0.2.0rc0/examples/schema_types.py +100 -0
  25. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/examples/simple.py +4 -2
  26. panel_reactflow-0.2.0rc0/examples/threejs_viewer.py +450 -0
  27. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/pixi.lock +1624 -1793
  28. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/pixi.toml +6 -6
  29. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/pyproject.toml +3 -0
  30. panel_reactflow-0.2.0rc0/src/panel_reactflow/__init__.py +26 -0
  31. panel_reactflow-0.2.0rc0/src/panel_reactflow/base.py +2233 -0
  32. panel_reactflow-0.2.0rc0/src/panel_reactflow/dist/css/reactflow.css +74 -0
  33. panel_reactflow-0.2.0rc0/src/panel_reactflow/dist/icons/gear.svg +1 -0
  34. panel_reactflow-0.2.0rc0/src/panel_reactflow/dist/panel-reactflow.bundle.css +1 -0
  35. panel_reactflow-0.2.0rc0/src/panel_reactflow/dist/panel-reactflow.bundle.js +82 -0
  36. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/src/panel_reactflow/models/reactflow.jsx +113 -150
  37. panel_reactflow-0.2.0rc0/src/panel_reactflow/schema.py +239 -0
  38. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/tests/conftest.py +17 -22
  39. panel_reactflow-0.2.0rc0/tests/test_api.py +565 -0
  40. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/tests/ui/test_ui.py +105 -19
  41. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/zensical.toml +12 -3
  42. panel_reactflow-0.0.1a1/docs/index.md +0 -6
  43. panel_reactflow-0.0.1a1/examples/advanced.py +0 -67
  44. panel_reactflow-0.0.1a1/src/panel_reactflow/__init__.py +0 -12
  45. panel_reactflow-0.0.1a1/src/panel_reactflow/base.py +0 -706
  46. panel_reactflow-0.0.1a1/tests/test_api.py +0 -94
  47. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/.copier-answers.yml +0 -0
  48. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/.gitattributes +0 -0
  49. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/.github/CODEOWNERS +0 -0
  50. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/.github/dependabot.yml +0 -0
  51. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/.github/workflows/build.yml +0 -0
  52. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/.github/workflows/test.yml +0 -0
  53. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/.gitignore +0 -0
  54. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/.pre-commit-config.yaml +0 -0
  55. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/.prettierrc +0 -0
  56. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/LICENSE.txt +0 -0
  57. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/MANIFEST.in +0 -0
  58. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/docs/assets/logo.svg +0 -0
  59. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/docs/examples.md +0 -0
  60. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/docs/reference/panel_reactflow.md +0 -0
  61. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/hatch_build.py +0 -0
  62. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/src/panel_reactflow/__version.py +0 -0
  63. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/src/panel_reactflow/py.typed +0 -0
  64. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/tests/__init__.py +0 -0
  65. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/tests/test_core.py +0 -0
  66. {panel_reactflow-0.0.1a1 → panel_reactflow-0.2.0rc0}/tests/ui/__init__.py +0 -0
@@ -2,8 +2,25 @@ name: Build documentation
2
2
 
3
3
  on:
4
4
  push:
5
- branches:
6
- - main
5
+ tags:
6
+ - "v[0-9]+.[0-9]+.[0-9]+"
7
+ - "v[0-9]+.[0-9]+.[0-9]+a[0-9]+"
8
+ - "v[0-9]+.[0-9]+.[0-9]+b[0-9]+"
9
+ - "v[0-9]+.[0-9]+.[0-9]+rc[0-9]+"
10
+ workflow_dispatch:
11
+ inputs:
12
+ target:
13
+ description: "Site to build and deploy"
14
+ type: choice
15
+ options:
16
+ - dev
17
+ - main
18
+ - dryrun
19
+ required: true
20
+ default: dryrun
21
+ schedule:
22
+ - cron: "0 17 * * SUN"
23
+
7
24
 
8
25
  # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
9
26
  permissions:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: panel-reactflow
3
- Version: 0.0.1a1
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
@@ -51,6 +51,8 @@ Description-Content-Type: text/markdown
51
51
 
52
52
  A Panel wrapper for the React Flow JS library.
53
53
 
54
+ ![panel-reactflow demo](https://assets.holoviz.org/panel-reactflow/videos/reactflow_demo.gif)
55
+
54
56
  ## Features
55
57
 
56
58
  - Python-first, JSON-serializable graph state
@@ -78,21 +80,23 @@ import panel as pn
78
80
 
79
81
  from panel_reactflow import ReactFlow
80
82
 
81
- pn.extension()
83
+ pn.extension("jsoneditor")
82
84
 
83
85
  nodes = [
84
86
  {
85
87
  "id": "n1",
86
88
  "position": {"x": 0, "y": 0},
87
89
  "type": "panel",
88
- "data": {"label": "Start"},
90
+ "label": "Start",
91
+ "data": {},
89
92
  "view": pn.pane.Markdown("Node 1 content"),
90
93
  },
91
94
  {
92
95
  "id": "n2",
93
96
  "position": {"x": 260, "y": 60},
94
97
  "type": "panel",
95
- "data": {"label": "End"},
98
+ "label": "End",
99
+ "data": {},
96
100
  "view": pn.pane.Markdown("Node 2 content"),
97
101
  },
98
102
  ]
@@ -8,6 +8,8 @@
8
8
 
9
9
  A Panel wrapper for the React Flow JS library.
10
10
 
11
+ ![panel-reactflow demo](https://assets.holoviz.org/panel-reactflow/videos/reactflow_demo.gif)
12
+
11
13
  ## Features
12
14
 
13
15
  - Python-first, JSON-serializable graph state
@@ -35,21 +37,23 @@ import panel as pn
35
37
 
36
38
  from panel_reactflow import ReactFlow
37
39
 
38
- pn.extension()
40
+ pn.extension("jsoneditor")
39
41
 
40
42
  nodes = [
41
43
  {
42
44
  "id": "n1",
43
45
  "position": {"x": 0, "y": 0},
44
46
  "type": "panel",
45
- "data": {"label": "Start"},
47
+ "label": "Start",
48
+ "data": {},
46
49
  "view": pn.pane.Markdown("Node 1 content"),
47
50
  },
48
51
  {
49
52
  "id": "n2",
50
53
  "position": {"x": 260, "y": 60},
51
54
  "type": "panel",
52
- "data": {"label": "End"},
55
+ "label": "End",
56
+ "data": {},
53
57
  "view": pn.pane.Markdown("Node 2 content"),
54
58
  },
55
59
  ]
@@ -0,0 +1,125 @@
1
+ # Declare Node & Edge Types
2
+
3
+ Node and edge types are lightweight descriptors that tell Panel-ReactFlow
4
+ **what kind of data a node or edge carries**. A type defines a name, an
5
+ optional display label, optional input/output ports (for nodes), and an
6
+ optional JSON Schema for its `data` payload.
7
+
8
+ Types are separate from editors. A type says "a *task* node has a
9
+ *status* string and a *priority* integer"; an editor says "render a
10
+ dropdown and a number input for those fields." This separation lets you
11
+ reuse the same type with different editors, or rely on the auto-generated
12
+ form.
13
+
14
+ ![Screenshot: multiple node types with different schemas](../assets/screenshots/declare-types.png)
15
+
16
+ ---
17
+
18
+ ## Node types
19
+
20
+ Use `NodeType` to describe a node type. Provide `inputs` and `outputs` to
21
+ control the handles (ports) shown on each side of the node.
22
+
23
+ ```python
24
+ from panel_reactflow import NodeType
25
+
26
+ task_schema = {
27
+ "type": "object",
28
+ "properties": {
29
+ "status": {"type": "string", "enum": ["idle", "running", "done"]},
30
+ "priority": {"type": "integer"},
31
+ },
32
+ }
33
+
34
+ node_types = {
35
+ "task": NodeType(
36
+ type="task",
37
+ label="Task",
38
+ schema=task_schema,
39
+ inputs=["in"],
40
+ outputs=["out"],
41
+ ),
42
+ }
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Edge types
48
+
49
+ Use `EdgeType` to describe an edge type. Edges with a schema get the same
50
+ auto-generated editor support as nodes.
51
+
52
+ ```python
53
+ from panel_reactflow import EdgeType
54
+
55
+ edge_types = {
56
+ "pipe": EdgeType(
57
+ type="pipe",
58
+ label="Pipe",
59
+ schema={
60
+ "type": "object",
61
+ "properties": {
62
+ "throughput": {"type": "number"},
63
+ "protocol": {"type": "string", "enum": ["tcp", "udp", "http"]},
64
+ },
65
+ },
66
+ ),
67
+ }
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Schema sources
73
+
74
+ The `schema` field accepts multiple formats. All are normalized to
75
+ JSON Schema before being sent to the frontend or used by editors.
76
+
77
+ | Source | Example |
78
+ |--------|---------|
79
+ | **JSON Schema dict** | `{"type": "object", "properties": {...}}` |
80
+ | **Param class** | A `param.Parameterized` subclass |
81
+ | **Pydantic model** | A `pydantic.BaseModel` subclass |
82
+
83
+ ### Param class shorthand
84
+
85
+ ```python
86
+ import param
87
+ from panel_reactflow import NodeType
88
+
89
+ class Job(param.Parameterized):
90
+ status = param.Selector(objects=["idle", "running", "done"])
91
+ retries = param.Integer(default=0)
92
+
93
+ node_types = {"job": NodeType(type="job", label="Job", schema=Job)}
94
+ ```
95
+
96
+ ### Pydantic model shorthand
97
+
98
+ ```python
99
+ from pydantic import BaseModel
100
+ from panel_reactflow import NodeType
101
+
102
+ class Config(BaseModel):
103
+ host: str = "localhost"
104
+ port: int = 8080
105
+
106
+ node_types = {"config": NodeType(type="config", label="Config", schema=Config)}
107
+ ```
108
+
109
+ ---
110
+
111
+ ## Register on ReactFlow
112
+
113
+ Pass types as dictionaries keyed by type name.
114
+
115
+ ```python
116
+ flow = ReactFlow(
117
+ nodes=nodes,
118
+ edges=edges,
119
+ node_types=node_types,
120
+ edge_types=edge_types,
121
+ )
122
+ ```
123
+
124
+ Types without a schema still work — the node or edge simply has no
125
+ schema-driven validation or auto-generated form.
@@ -0,0 +1,239 @@
1
+ # Define Editors
2
+
3
+ Editors give users a way to view and modify the `data` payload of a node or
4
+ edge at runtime. Panel-ReactFlow **decouples editors from types**: you
5
+ register editors separately, so you can swap editing UI without touching
6
+ your type definitions.
7
+
8
+ Both node editors and edge editors share the exact same interface. If you
9
+ can build a node editor, you already know how to build an edge editor.
10
+
11
+ When a user selects a node (or an edge), Panel-ReactFlow looks up the
12
+ matching editor, creates the view, and displays it in the configured panel.
13
+ If no editor is registered for a type, the built-in `SchemaEditor` is
14
+ used: it auto-generates a form from the JSON Schema if one is present,
15
+ or falls back to a raw JSON editor.
16
+
17
+ ![Screenshot: a node with schema-driven form editor open in the side panel](../assets/screenshots/define-editors-node.png)
18
+
19
+ ---
20
+
21
+ ## Editor signature
22
+
23
+ Every editor — whether a simple function, a lambda, or a class — receives
24
+ the same arguments:
25
+
26
+ ```
27
+ editor(data, schema, *, id, type, on_patch) -> Viewable
28
+ ```
29
+
30
+ | Argument | Description |
31
+ |------------|-------------|
32
+ | `data` | The current `data` dict of the node or edge. |
33
+ | `schema` | The normalized JSON Schema (or `None`). |
34
+ | `id` | The node or edge ID. |
35
+ | `type` | The node or edge type name. |
36
+ | `on_patch` | Callback: call `on_patch({"key": value})` to push a partial update. |
37
+
38
+ ---
39
+
40
+ ## Built-in editors
41
+
42
+ Panel-ReactFlow ships two built-in editor classes:
43
+
44
+ | Class | Behavior |
45
+ |--------------------|----------|
46
+ | `SchemaEditor` | Renders a form generated from the JSON Schema. Falls back to a raw JSON editor when no schema is available. **This is the default.** |
47
+ | `JsonEditor` | Always renders a raw JSON editor (powered by `panel.pane.JSON`). |
48
+
49
+ ```python
50
+ from panel_reactflow import JsonEditor, ReactFlow, SchemaEditor
51
+
52
+ flow = ReactFlow(
53
+ nodes=nodes,
54
+ edges=edges,
55
+ default_node_editor=SchemaEditor, # already the default
56
+ default_edge_editor=JsonEditor, # override for edges
57
+ )
58
+ ```
59
+
60
+ ---
61
+
62
+ ## Node editors
63
+
64
+ ### Register a callable editor for a node type
65
+
66
+ The simplest way to provide a custom node editor is a plain function that
67
+ returns a Panel viewable.
68
+
69
+ ```python
70
+ import panel_material_ui as pmui
71
+ from panel_reactflow import ReactFlow
72
+
73
+ def metric_editor(data, schema, *, id, type, on_patch):
74
+ value = pmui.FloatSlider(value=data.get("value", 0), start=0, end=100)
75
+ unit = pmui.Select(value=data.get("unit", "ms"), options=["ms", "s", "%"])
76
+ value.param.watch(lambda e: on_patch({"value": e.new}), "value")
77
+ unit.param.watch(lambda e: on_patch({"unit": e.new}), "value")
78
+ return pmui.Column(value, unit)
79
+
80
+ flow = ReactFlow(
81
+ nodes=nodes,
82
+ edges=edges,
83
+ node_editors={"metric": metric_editor},
84
+ )
85
+ ```
86
+
87
+ ### Set a default node editor
88
+
89
+ If you want *all* node types to use the same custom editor, set
90
+ `default_node_editor` instead of mapping each type individually.
91
+
92
+ ```python
93
+ flow = ReactFlow(
94
+ nodes=nodes,
95
+ edges=edges,
96
+ default_node_editor=metric_editor,
97
+ )
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Edge editors
103
+
104
+ Edge editors work identically. Register them via `edge_editors` (keyed by
105
+ edge type) or `default_edge_editor` for a blanket default.
106
+
107
+ ![Screenshot: an edge editor open in the side panel](../assets/screenshots/define-editors-edge.png)
108
+
109
+ ### Schema-driven edge editor
110
+
111
+ If you declare an `EdgeType` with a schema and do not provide an explicit
112
+ editor, the default `SchemaEditor` auto-generates a form — the same
113
+ as for nodes.
114
+
115
+ ```python
116
+ from panel_reactflow import EdgeType, ReactFlow
117
+
118
+ edge_types = {
119
+ "pipe": EdgeType(
120
+ type="pipe",
121
+ label="Pipe",
122
+ schema={
123
+ "type": "object",
124
+ "properties": {
125
+ "throughput": {"type": "number", "title": "Throughput"},
126
+ "protocol": {
127
+ "type": "string",
128
+ "enum": ["tcp", "udp", "http"],
129
+ "title": "Protocol",
130
+ },
131
+ },
132
+ },
133
+ ),
134
+ }
135
+
136
+ flow = ReactFlow(
137
+ nodes=nodes,
138
+ edges=edges,
139
+ edge_types=edge_types,
140
+ # No edge_editors needed — SchemaEditor handles "pipe" automatically.
141
+ )
142
+ ```
143
+
144
+ ### Custom callable edge editor
145
+
146
+ ```python
147
+ import panel_material_ui as pmui
148
+ from panel_reactflow import EdgeType, ReactFlow
149
+
150
+ def signal_editor(data, schema, *, id, type, on_patch):
151
+ freq = pmui.FloatSlider(
152
+ value=data.get("frequency", 1.0), start=0.1, end=100, step=0.1,
153
+ label="Frequency (Hz)",
154
+ )
155
+ active = pmui.Checkbox(value=data.get("active", True), label="Active")
156
+ freq.param.watch(lambda e: on_patch({"frequency": e.new}), "value")
157
+ active.param.watch(lambda e: on_patch({"active": e.new}), "value")
158
+ return pmui.Paper(pmui.Column(freq, active, margin=5), margin=0)
159
+
160
+ flow = ReactFlow(
161
+ nodes=nodes,
162
+ edges=edges,
163
+ edge_types={"signal": EdgeType(type="signal", label="Signal")},
164
+ edge_editors={"signal": signal_editor},
165
+ )
166
+ ```
167
+
168
+ ---
169
+
170
+ ## Class-based editors
171
+
172
+ For editors with complex state or lifecycle needs, subclass `Editor`.
173
+ The base class stores `data`, `schema`, `id`, `type`, and `on_patch` for
174
+ you. Implement `__panel__()` to return the view.
175
+
176
+ Class-based editors work for both nodes and edges.
177
+
178
+ ```python
179
+ import panel as pn
180
+ from panel_reactflow import Editor
181
+
182
+ class TitleEditor(Editor):
183
+ def __init__(self, data, schema, **kwargs):
184
+ super().__init__(data, schema, **kwargs)
185
+ self._input = pn.widgets.TextInput(value=data.get("title", ""))
186
+ self._input.param.watch(self._on_title_change, "value")
187
+
188
+ def _on_title_change(self, event):
189
+ if self._on_patch is not None:
190
+ self._on_patch({"title": event.new})
191
+
192
+ def __panel__(self):
193
+ return self._input
194
+ ```
195
+
196
+ Register it like any callable:
197
+
198
+ ```python
199
+ flow = ReactFlow(
200
+ nodes=nodes, edges=edges,
201
+ node_editors={"article": TitleEditor},
202
+ edge_editors={"comment": TitleEditor}, # reuse the same class
203
+ )
204
+ ```
205
+
206
+ ---
207
+
208
+ ## Editor display modes
209
+
210
+ Control where node editors appear with `editor_mode`:
211
+
212
+ | Mode | Description |
213
+ |-----------|-------------|
214
+ | `"side"` | Side panel to the right of the canvas. |
215
+ | `"node"` | Inline, directly inside the selected node. |
216
+ | `"toolbar"` | In the top toolbar area. |
217
+
218
+ Edge editors always appear in the **side panel** (right side of the
219
+ canvas).
220
+
221
+ ```python
222
+ flow = ReactFlow(
223
+ nodes=nodes,
224
+ edges=edges,
225
+ editor_mode="side",
226
+ )
227
+ ```
228
+
229
+ ---
230
+
231
+ ## Tips
232
+
233
+ - Call `on_patch({"key": value})` for data changes. Labels are top-level
234
+ and should be updated by replacing the node/edge in `flow.nodes` or
235
+ `flow.edges`.
236
+ - You can mix strategies: use schema-driven editors for most types and
237
+ custom editors only where you need full control.
238
+ - The same editor class or function can be registered for both node and
239
+ edge types.