panel-reactflow 0.2.0rc0__tar.gz → 0.3.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 (92) hide show
  1. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/.github/workflows/docs.yml +17 -1
  2. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/.github/workflows/test.yml +1 -0
  3. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/PKG-INFO +3 -3
  4. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/README.md +2 -2
  5. panel_reactflow-0.3.0/docs/assets/screenshots/declare-types.png +0 -0
  6. panel_reactflow-0.3.0/docs/assets/screenshots/define-editors-edge.png +0 -0
  7. panel_reactflow-0.3.0/docs/assets/screenshots/define-editors-node.png +0 -0
  8. panel_reactflow-0.3.0/docs/assets/screenshots/define-nodes-edges.png +0 -0
  9. panel_reactflow-0.3.0/docs/assets/screenshots/embed-views-in-nodes.png +0 -0
  10. panel_reactflow-0.3.0/docs/assets/screenshots/examples/advanced.png +0 -0
  11. panel_reactflow-0.3.0/docs/assets/screenshots/examples/custom_editor.png +0 -0
  12. panel_reactflow-0.3.0/docs/assets/screenshots/examples/edge_editors.png +0 -0
  13. panel_reactflow-0.3.0/docs/assets/screenshots/examples/node_edge_instances.png +0 -0
  14. panel_reactflow-0.3.0/docs/assets/screenshots/examples/schema_types.png +0 -0
  15. panel_reactflow-0.3.0/docs/assets/screenshots/examples/simple.png +0 -0
  16. panel_reactflow-0.3.0/docs/assets/screenshots/examples/threejs_viewer.png +0 -0
  17. panel_reactflow-0.3.0/docs/assets/screenshots/examples/threejs_viewer_instances.png +0 -0
  18. panel_reactflow-0.3.0/docs/assets/screenshots/quickstart.png +0 -0
  19. panel_reactflow-0.3.0/docs/assets/screenshots/react-to-events.png +0 -0
  20. panel_reactflow-0.3.0/docs/assets/screenshots/style-nodes-edges.png +0 -0
  21. panel_reactflow-0.3.0/docs/examples/advanced.md +12 -0
  22. panel_reactflow-0.3.0/docs/examples/custom-editor.md +12 -0
  23. panel_reactflow-0.3.0/docs/examples/edge-editors.md +12 -0
  24. panel_reactflow-0.3.0/docs/examples/index.md +64 -0
  25. panel_reactflow-0.3.0/docs/examples/node-edge-instances.md +12 -0
  26. panel_reactflow-0.3.0/docs/examples/schema-types.md +12 -0
  27. panel_reactflow-0.3.0/docs/examples/simple.md +11 -0
  28. panel_reactflow-0.3.0/docs/examples/threejs-viewer-instances.md +12 -0
  29. panel_reactflow-0.3.0/docs/examples/threejs-viewer.md +12 -0
  30. panel_reactflow-0.3.0/docs/how-to/declare-types.md +239 -0
  31. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/docs/how-to/define-editors.md +110 -0
  32. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/docs/how-to/define-nodes-edges.md +162 -3
  33. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/docs/how-to/embed-views-in-nodes.md +68 -0
  34. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/docs/how-to/react-to-events.md +67 -9
  35. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/docs/how-to/style-nodes-edges.md +112 -0
  36. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/docs/index.md +4 -0
  37. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/docs/quickstart.md +0 -6
  38. panel_reactflow-0.3.0/docs/releases.md +98 -0
  39. panel_reactflow-0.3.0/examples/node_edge_instances.py +138 -0
  40. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/examples/threejs_viewer.py +2 -2
  41. panel_reactflow-0.3.0/examples/threejs_viewer_instances.py +335 -0
  42. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/pixi.lock +1974 -1954
  43. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/src/panel_reactflow/__init__.py +4 -0
  44. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/src/panel_reactflow/base.py +785 -117
  45. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/src/panel_reactflow/dist/css/reactflow.css +15 -8
  46. panel_reactflow-0.3.0/src/panel_reactflow/dist/panel-reactflow.bundle.js +88 -0
  47. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/src/panel_reactflow/models/reactflow.jsx +190 -13
  48. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/tests/test_api.py +312 -57
  49. panel_reactflow-0.3.0/tests/test_core.py +120 -0
  50. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/tests/ui/test_ui.py +4 -7
  51. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/zensical.toml +11 -1
  52. panel_reactflow-0.2.0rc0/docs/assets/screenshots/declare-types.png +0 -0
  53. panel_reactflow-0.2.0rc0/docs/assets/screenshots/define-editors-edge.png +0 -0
  54. panel_reactflow-0.2.0rc0/docs/assets/screenshots/define-editors-node.png +0 -0
  55. panel_reactflow-0.2.0rc0/docs/assets/screenshots/define-nodes-edges.png +0 -0
  56. panel_reactflow-0.2.0rc0/docs/assets/screenshots/embed-views-in-nodes.png +0 -0
  57. panel_reactflow-0.2.0rc0/docs/assets/screenshots/quickstart.png +0 -0
  58. panel_reactflow-0.2.0rc0/docs/assets/screenshots/react-to-events.png +0 -0
  59. panel_reactflow-0.2.0rc0/docs/assets/screenshots/style-nodes-edges.png +0 -0
  60. panel_reactflow-0.2.0rc0/docs/examples.md +0 -13
  61. panel_reactflow-0.2.0rc0/docs/how-to/declare-types.md +0 -125
  62. panel_reactflow-0.2.0rc0/docs/releases.md +0 -42
  63. panel_reactflow-0.2.0rc0/src/panel_reactflow/dist/panel-reactflow.bundle.js +0 -82
  64. panel_reactflow-0.2.0rc0/tests/test_core.py +0 -8
  65. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/.copier-answers.yml +0 -0
  66. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/.gitattributes +0 -0
  67. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/.github/CODEOWNERS +0 -0
  68. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/.github/dependabot.yml +0 -0
  69. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/.github/workflows/build.yml +0 -0
  70. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/.gitignore +0 -0
  71. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/.pre-commit-config.yaml +0 -0
  72. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/.prettierrc +0 -0
  73. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/LICENSE.txt +0 -0
  74. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/MANIFEST.in +0 -0
  75. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/docs/assets/logo.svg +0 -0
  76. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/docs/reference/panel_reactflow.md +0 -0
  77. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/examples/advanced.py +0 -0
  78. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/examples/custom_editor.py +0 -0
  79. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/examples/edge_editors.py +0 -0
  80. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/examples/schema_types.py +0 -0
  81. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/examples/simple.py +0 -0
  82. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/hatch_build.py +0 -0
  83. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/pixi.toml +0 -0
  84. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/pyproject.toml +0 -0
  85. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/src/panel_reactflow/__version.py +0 -0
  86. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/src/panel_reactflow/dist/icons/gear.svg +0 -0
  87. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/src/panel_reactflow/dist/panel-reactflow.bundle.css +0 -0
  88. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/src/panel_reactflow/py.typed +0 -0
  89. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/src/panel_reactflow/schema.py +0 -0
  90. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/tests/__init__.py +0 -0
  91. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/tests/conftest.py +0 -0
  92. {panel_reactflow-0.2.0rc0 → panel_reactflow-0.3.0}/tests/ui/__init__.py +0 -0
@@ -70,6 +70,22 @@ jobs:
70
70
  runs-on: ubuntu-latest
71
71
  needs: build
72
72
  steps:
73
- - name: Deploy to GitHub Pages
73
+ - name: Deploy dev
74
+ uses: peaceiris/actions-gh-pages@v4
75
+ # Dev site built on PRs
76
+ if: |
77
+ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) ||
78
+ (github.event_name == 'workflow_dispatch' && github.event.inputs.target == 'dev') ||
79
+ (github.event_name == 'push' && (contains(steps.vars.outputs.tag, 'a') || contains(steps.vars.outputs.tag, 'b') || contains(steps.vars.outputs.tag, 'rc')))
80
+ with:
81
+ personal_token: ${{ secrets.HOLOVIZ_ACCESS_TOKEN }}
82
+ external_repository: holoviz-dev/panel-reactflow
83
+ publish_dir: ./builtdocs
84
+ force_orphan: true
85
+ - name: Deploy main
86
+ if: |
87
+ (github.event_name != 'pull_request') &&
88
+ ((github.event_name == 'workflow_dispatch' && github.event.inputs.target == 'main') ||
89
+ (github.event_name == 'push' && !(contains(steps.vars.outputs.tag, 'a') || contains(steps.vars.outputs.tag, 'b') || contains(steps.vars.outputs.tag, 'rc'))))
74
90
  id: deployment
75
91
  uses: actions/deploy-pages@v4
@@ -135,6 +135,7 @@ jobs:
135
135
  environment: ["test-ui"]
136
136
  timeout-minutes: 60
137
137
  env:
138
+ PYTHONUTF8: 1
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.2.0rc0
3
+ Version: 0.3.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
@@ -59,7 +59,7 @@ A Panel wrapper for the React Flow JS library.
59
59
  - Panel viewables inside nodes via node ``view`` entries
60
60
  - Interactive editing (drag/select/connect/delete) with sync back to Python
61
61
  - Optional schema definitions for node/edge properties
62
- - Event callbacks via `ReactFlow.on(...)` for app-level handling
62
+ - Event callbacks via `ReactFlow.on(...)` for app-level handling (callback signature: `callback(payload, flow)`)
63
63
 
64
64
  ## Pin your version!
65
65
 
@@ -112,7 +112,7 @@ flow = ReactFlow(
112
112
  flow
113
113
  ```
114
114
 
115
- For property schemas and richer editors, provide `node_types`/`edge_types` with `PropertySpec` and handle changes via `ReactFlow.on(...)`.
115
+ For property schemas and richer editors, provide `node_types`/`edge_types` with `PropertySpec` and handle changes via `ReactFlow.on(...)`. `.on` callbacks receive the event payload as the first argument and can optionally accept the `ReactFlow` instance as a second argument.
116
116
 
117
117
  ## Development
118
118
 
@@ -16,7 +16,7 @@ A Panel wrapper for the React Flow JS library.
16
16
  - Panel viewables inside nodes via node ``view`` entries
17
17
  - Interactive editing (drag/select/connect/delete) with sync back to Python
18
18
  - Optional schema definitions for node/edge properties
19
- - Event callbacks via `ReactFlow.on(...)` for app-level handling
19
+ - Event callbacks via `ReactFlow.on(...)` for app-level handling (callback signature: `callback(payload, flow)`)
20
20
 
21
21
  ## Pin your version!
22
22
 
@@ -69,7 +69,7 @@ flow = ReactFlow(
69
69
  flow
70
70
  ```
71
71
 
72
- For property schemas and richer editors, provide `node_types`/`edge_types` with `PropertySpec` and handle changes via `ReactFlow.on(...)`.
72
+ For property schemas and richer editors, provide `node_types`/`edge_types` with `PropertySpec` and handle changes via `ReactFlow.on(...)`. `.on` callbacks receive the event payload as the first argument and can optionally accept the `ReactFlow` instance as a second argument.
73
73
 
74
74
  ## Development
75
75
 
@@ -0,0 +1,12 @@
1
+ # Advanced
2
+
3
+ Schema-driven editor workflow with a custom node type, type stylesheets,
4
+ and top-panel event feedback.
5
+
6
+ ![Screenshot: advanced example](../assets/screenshots/examples/advanced.png)
7
+
8
+ ## Source
9
+
10
+ ```python
11
+ --8<-- "examples/advanced.py"
12
+ ```
@@ -0,0 +1,12 @@
1
+ # Custom Editor
2
+
3
+ Registers a callable editor for `metric` nodes and pushes incremental updates
4
+ using `on_patch`.
5
+
6
+ ![Screenshot: custom editor example](../assets/screenshots/examples/custom_editor.png)
7
+
8
+ ## Source
9
+
10
+ ```python
11
+ --8<-- "examples/custom_editor.py"
12
+ ```
@@ -0,0 +1,12 @@
1
+ # Edge Editors
2
+
3
+ Shows schema-backed edge editing plus a custom callable edge editor for
4
+ specialized edge types.
5
+
6
+ ![Screenshot: edge editors example](../assets/screenshots/examples/edge_editors.png)
7
+
8
+ ## Source
9
+
10
+ ```python
11
+ --8<-- "examples/edge_editors.py"
12
+ ```
@@ -0,0 +1,64 @@
1
+ # Examples Gallery
2
+
3
+ Browse runnable examples from `examples/`. Each card links to a dedicated page
4
+ with a screenshot and full source code.
5
+
6
+ <div class="grid cards" markdown>
7
+
8
+ - ![Advanced example](../assets/screenshots/examples/advanced.png)
9
+
10
+ ---
11
+
12
+ **[Advanced](advanced.md)**
13
+ Schema-driven task nodes with event tracking.
14
+
15
+ - ![Custom editor example](../assets/screenshots/examples/custom_editor.png)
16
+
17
+ ---
18
+
19
+ **[Custom Editor](custom-editor.md)**
20
+ Callable node editor with custom widgets.
21
+
22
+ - ![Edge editors example](../assets/screenshots/examples/edge_editors.png)
23
+
24
+ ---
25
+
26
+ **[Edge Editors](edge-editors.md)**
27
+ Schema-backed and callable edge editors.
28
+
29
+ - ![Node/edge instances example](../assets/screenshots/examples/node_edge_instances.png)
30
+
31
+ ---
32
+
33
+ **[Node/Edge Instances](node-edge-instances.md)**
34
+ Class-based nodes and edges with hooks.
35
+
36
+ - ![Schema types example](../assets/screenshots/examples/schema_types.png)
37
+
38
+ ---
39
+
40
+ **[Schema Types](schema-types.md)**
41
+ Multiple node types, each with its own schema.
42
+
43
+ - ![Simple example](../assets/screenshots/examples/simple.png)
44
+
45
+ ---
46
+
47
+ **[Simple](simple.md)**
48
+ Minimal graph setup with top panel.
49
+
50
+ - ![ThreeJS viewer example](../assets/screenshots/examples/threejs_viewer.png)
51
+
52
+ ---
53
+
54
+ **[ThreeJS Viewer](threejs-viewer.md)**
55
+ Graph-driven 3D cube viewer controls.
56
+
57
+ - ![ThreeJS viewer instances example](../assets/screenshots/examples/threejs_viewer_instances.png)
58
+
59
+ ---
60
+
61
+ **[ThreeJS Viewer (Instances)](threejs-viewer-instances.md)**
62
+ ThreeJS viewer with Node and Edge instances.
63
+
64
+ </div>
@@ -0,0 +1,12 @@
1
+ # Node/Edge Instances
2
+
3
+ Uses `Node` and `Edge` subclasses for rich behavior, custom editors, and event
4
+ hooks while still rendering in a standard ReactFlow canvas.
5
+
6
+ ![Screenshot: node and edge instances example](../assets/screenshots/examples/node_edge_instances.png)
7
+
8
+ ## Source
9
+
10
+ ```python
11
+ --8<-- "examples/node_edge_instances.py"
12
+ ```
@@ -0,0 +1,12 @@
1
+ # Schema Types
2
+
3
+ Demonstrates multiple node types where each type contributes its own schema,
4
+ including both Param-derived and raw JSON Schema definitions.
5
+
6
+ ![Screenshot: schema types example](../assets/screenshots/examples/schema_types.png)
7
+
8
+ ## Source
9
+
10
+ ```python
11
+ --8<-- "examples/schema_types.py"
12
+ ```
@@ -0,0 +1,11 @@
1
+ # Simple
2
+
3
+ A minimal two-node graph setup with an edge and an optional top panel.
4
+
5
+ ![Screenshot: simple example](../assets/screenshots/examples/simple.png)
6
+
7
+ ## Source
8
+
9
+ ```python
10
+ --8<-- "examples/simple.py"
11
+ ```
@@ -0,0 +1,12 @@
1
+ # ThreeJS Viewer (Instances)
2
+
3
+ The ThreeJS viewer example implemented with `Node` and `Edge` subclass
4
+ instances for object-oriented graph behavior.
5
+
6
+ ![Screenshot: threejs viewer instances example](../assets/screenshots/examples/threejs_viewer_instances.png)
7
+
8
+ ## Source
9
+
10
+ ```python
11
+ --8<-- "examples/threejs_viewer_instances.py"
12
+ ```
@@ -0,0 +1,12 @@
1
+ # ThreeJS Viewer
2
+
3
+ Interactive 3D cube rendering controlled through graph-connected parameter
4
+ nodes.
5
+
6
+ ![Screenshot: threejs viewer example](../assets/screenshots/examples/threejs_viewer.png)
7
+
8
+ ## Source
9
+
10
+ ```python
11
+ --8<-- "examples/threejs_viewer.py"
12
+ ```
@@ -0,0 +1,239 @@
1
+ # Declare Node & Edge Types
2
+
3
+ Node and edge types are lightweight descriptors that define **what data each
4
+ kind of node/edge carries**. A type can provide:
5
+
6
+ - a type name (`type`)
7
+ - a display label (`label`)
8
+ - node handles (`inputs` / `outputs`)
9
+ - a schema for the `data` payload (`schema`)
10
+
11
+ Types are separate from editors. A type defines structure; an editor defines
12
+ the UI used to edit it.
13
+
14
+ ![Screenshot: multiple node types with different schemas](../assets/screenshots/declare-types.png)
15
+
16
+ ---
17
+
18
+ ## Complete runnable example
19
+
20
+ This script is a minimal, working example that produces the visualization
21
+ shown above.
22
+
23
+ ```python
24
+ import param
25
+ import panel as pn
26
+
27
+ from panel_reactflow import EdgeType, NodeType, ReactFlow
28
+
29
+ pn.extension("jsoneditor")
30
+
31
+
32
+ class Job(param.Parameterized):
33
+ status = param.Selector(objects=["idle", "running", "done"])
34
+ retries = param.Integer(default=0)
35
+
36
+
37
+ decision_schema = {
38
+ "type": "object",
39
+ "properties": {
40
+ "question": {"type": "string", "title": "Question"},
41
+ "outcome": {
42
+ "type": "string",
43
+ "enum": ["yes", "no", "maybe"],
44
+ "title": "Outcome",
45
+ },
46
+ },
47
+ }
48
+
49
+ node_types = {
50
+ "job": NodeType(type="job", label="Job", schema=Job, inputs=["in"], outputs=["out"]),
51
+ "decision": NodeType(
52
+ type="decision",
53
+ label="Decision",
54
+ schema=decision_schema,
55
+ inputs=["in"],
56
+ outputs=["yes", "no"],
57
+ ),
58
+ }
59
+
60
+ edge_types = {
61
+ "flow": EdgeType(
62
+ type="flow",
63
+ label="Flow",
64
+ schema={
65
+ "type": "object",
66
+ "properties": {"weight": {"type": "number", "title": "Weight"}},
67
+ },
68
+ ),
69
+ }
70
+
71
+ nodes = [
72
+ {
73
+ "id": "j1",
74
+ "type": "job",
75
+ "label": "Fetch Data",
76
+ "position": {"x": 0, "y": 0},
77
+ "data": {"status": "idle", "retries": 0},
78
+ },
79
+ {
80
+ "id": "d1",
81
+ "type": "decision",
82
+ "label": "Valid?",
83
+ "position": {"x": 300, "y": 250},
84
+ "data": {"question": "Is data valid?", "outcome": "yes"},
85
+ },
86
+ {
87
+ "id": "j2",
88
+ "type": "job",
89
+ "label": "Process",
90
+ "position": {"x": 600, "y": 400},
91
+ "data": {"status": "running", "retries": 1},
92
+ },
93
+ ]
94
+
95
+ edges = [
96
+ {"id": "e1", "source": "j1", "target": "d1", "type": "flow", "data": {"weight": 1.0}},
97
+ {"id": "e2", "source": "d1", "target": "j2", "type": "flow", "data": {"weight": 0.8}},
98
+ ]
99
+
100
+ TASK_NODE_CSS = """
101
+ .react-flow__node-job {
102
+ background-color: white;
103
+ border-radius: 8px;
104
+ border: 1.5px solid #7c3aed;
105
+ }
106
+
107
+ .react-flow__node-decision {
108
+ background-color: white;
109
+ border-radius: 8px;
110
+ border: 1.5px solid green;
111
+ }
112
+ """
113
+
114
+ flow = ReactFlow(
115
+ nodes=nodes,
116
+ edges=edges,
117
+ node_types=node_types,
118
+ edge_types=edge_types,
119
+ editor_mode="node",
120
+ sizing_mode="stretch_both",
121
+ stylesheets=[TASK_NODE_CSS]
122
+ )
123
+
124
+ pn.Column(flow, sizing_mode="stretch_both").servable()
125
+ ```
126
+
127
+ ## How this code maps to the visualization
128
+
129
+ - `node_types["job"]` and `node_types["decision"]` define the two node kinds you see.
130
+ - `inputs` and `outputs` define the left/right handles rendered on each node.
131
+ - `edge_types["flow"]` defines the edge payload schema used by both connections.
132
+ - `nodes` controls labels (`Fetch Data`, `Valid?`, `Process`) and positions.
133
+ - `editor_mode="side"` makes selection open the schema-driven editor in the right panel.
134
+
135
+ ---
136
+
137
+ ## Node type snippet
138
+
139
+ Use `NodeType` to define node handles and payload schema.
140
+
141
+ ```python
142
+ from panel_reactflow import NodeType
143
+
144
+ task_schema = {
145
+ "type": "object",
146
+ "properties": {
147
+ "status": {"type": "string", "enum": ["idle", "running", "done"]},
148
+ "priority": {"type": "integer"},
149
+ },
150
+ }
151
+
152
+ node_types = {
153
+ "task": NodeType(
154
+ type="task",
155
+ label="Task",
156
+ schema=task_schema,
157
+ inputs=["in"],
158
+ outputs=["out"],
159
+ ),
160
+ }
161
+ ```
162
+
163
+ ## Edge type snippet
164
+
165
+ Use `EdgeType` for edge payload schema and label.
166
+
167
+ ```python
168
+ from panel_reactflow import EdgeType
169
+
170
+ edge_types = {
171
+ "pipe": EdgeType(
172
+ type="pipe",
173
+ label="Pipe",
174
+ schema={
175
+ "type": "object",
176
+ "properties": {
177
+ "throughput": {"type": "number"},
178
+ "protocol": {"type": "string", "enum": ["tcp", "udp", "http"]},
179
+ },
180
+ },
181
+ ),
182
+ }
183
+ ```
184
+
185
+ ---
186
+
187
+ ## Schema sources
188
+
189
+ The `schema` field accepts multiple inputs and normalizes them to JSON Schema.
190
+
191
+ | Source | Example |
192
+ |--------|---------|
193
+ | **JSON Schema dict** | `{"type": "object", "properties": {...}}` |
194
+ | **Param class** | A `param.Parameterized` subclass |
195
+ | **Pydantic model** | A `pydantic.BaseModel` subclass |
196
+
197
+ ### Param class shorthand
198
+
199
+ ```python
200
+ import param
201
+ from panel_reactflow import NodeType
202
+
203
+ class Job(param.Parameterized):
204
+ status = param.Selector(objects=["idle", "running", "done"])
205
+ retries = param.Integer(default=0)
206
+
207
+ node_types = {"job": NodeType(type="job", label="Job", schema=Job)}
208
+ ```
209
+
210
+ ### Pydantic model shorthand
211
+
212
+ ```python
213
+ from pydantic import BaseModel
214
+ from panel_reactflow import NodeType
215
+
216
+ class Config(BaseModel):
217
+ host: str = "localhost"
218
+ port: int = 8080
219
+
220
+ node_types = {"config": NodeType(type="config", label="Config", schema=Config)}
221
+ ```
222
+
223
+ ---
224
+
225
+ ## Register on `ReactFlow`
226
+
227
+ Pass `node_types` and `edge_types` as dictionaries keyed by type name:
228
+
229
+ ```python
230
+ flow = ReactFlow(
231
+ nodes=nodes,
232
+ edges=edges,
233
+ node_types=node_types,
234
+ edge_types=edge_types,
235
+ )
236
+ ```
237
+
238
+ Types without a schema still work; they just do not get schema-driven
239
+ validation or auto-generated forms.
@@ -18,6 +18,65 @@ or falls back to a raw JSON editor.
18
18
 
19
19
  ---
20
20
 
21
+ ## Complete runnable example (node editor screenshot)
22
+
23
+ This script is a minimal, working example for the screenshot above. Run it,
24
+ then click the `Start` node to open the schema-driven editor in the side panel.
25
+
26
+ ```python
27
+ import panel as pn
28
+
29
+ from panel_reactflow import NodeType, ReactFlow
30
+
31
+ pn.extension("jsoneditor")
32
+
33
+ task_schema = {
34
+ "type": "object",
35
+ "properties": {
36
+ "status": {"type": "string", "enum": ["idle", "running", "done"], "title": "Status"},
37
+ "priority": {"type": "integer", "title": "Priority"},
38
+ "notes": {"type": "string", "title": "Notes"},
39
+ },
40
+ }
41
+
42
+ nodes = [
43
+ {
44
+ "id": "start",
45
+ "type": "task",
46
+ "label": "Start",
47
+ "position": {"x": 0, "y": 0},
48
+ "data": {"status": "idle", "priority": 1, "notes": ""},
49
+ },
50
+ {
51
+ "id": "finish",
52
+ "type": "task",
53
+ "label": "Finish",
54
+ "position": {"x": 300, "y": 80},
55
+ "data": {"status": "done", "priority": 2, "notes": "All clear"},
56
+ },
57
+ ]
58
+
59
+ edges = [{"id": "e1", "source": "start", "target": "finish"}]
60
+
61
+ flow = ReactFlow(
62
+ nodes=nodes,
63
+ edges=edges,
64
+ node_types={"task": NodeType(type="task", label="Task", schema=task_schema)},
65
+ editor_mode="side",
66
+ sizing_mode="stretch_both",
67
+ )
68
+
69
+ pn.Column(flow, sizing_mode="stretch_both").servable()
70
+ ```
71
+
72
+ ## How this code maps to the node-editor screenshot
73
+
74
+ - `task_schema` defines fields rendered in the side-panel form.
75
+ - `node_types={"task": ...}` binds that schema to both `task` nodes.
76
+ - Clicking a node selects it and opens its editor because `editor_mode="side"`.
77
+
78
+ ---
79
+
21
80
  ## Editor signature
22
81
 
23
82
  Every editor — whether a simple function, a lambda, or a class — receives
@@ -106,6 +165,57 @@ edge type) or `default_edge_editor` for a blanket default.
106
165
 
107
166
  ![Screenshot: an edge editor open in the side panel](../assets/screenshots/define-editors-edge.png)
108
167
 
168
+ ### Complete runnable example (edge editor screenshot)
169
+
170
+ This script reproduces the edge-editor screenshot. Run it, then click the
171
+ `pipe` edge to open its schema-driven editor.
172
+
173
+ ```python
174
+ import panel as pn
175
+
176
+ from panel_reactflow import EdgeType, NodeType, ReactFlow
177
+
178
+ pn.extension("jsoneditor")
179
+
180
+ pipe_schema = {
181
+ "type": "object",
182
+ "properties": {
183
+ "throughput": {"type": "number", "title": "Throughput"},
184
+ "protocol": {
185
+ "type": "string",
186
+ "enum": ["tcp", "udp", "http"],
187
+ "title": "Protocol",
188
+ },
189
+ },
190
+ }
191
+
192
+ nodes = [
193
+ {"id": "src", "type": "device", "label": "Source", "position": {"x": 0, "y": 0}, "data": {}},
194
+ {"id": "sink", "type": "device", "label": "Sink", "position": {"x": 400, "y": 0}, "data": {}},
195
+ ]
196
+
197
+ edges = [
198
+ {
199
+ "id": "e1",
200
+ "source": "src",
201
+ "target": "sink",
202
+ "type": "pipe",
203
+ "label": "pipe",
204
+ "data": {"throughput": 100.0, "protocol": "tcp"},
205
+ },
206
+ ]
207
+
208
+ flow = ReactFlow(
209
+ nodes=nodes,
210
+ edges=edges,
211
+ node_types={"device": NodeType(type="device", label="Device")},
212
+ edge_types={"pipe": EdgeType(type="pipe", label="Pipe", schema=pipe_schema)},
213
+ sizing_mode="stretch_both",
214
+ )
215
+
216
+ pn.Column(flow, sizing_mode="stretch_both").servable()
217
+ ```
218
+
109
219
  ### Schema-driven edge editor
110
220
 
111
221
  If you declare an `EdgeType` with a schema and do not provide an explicit