panel-reactflow 0.3.0rc0__tar.gz → 0.3.1__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 (80) hide show
  1. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/.github/workflows/build.yml +4 -4
  2. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/.github/workflows/docs.yml +21 -5
  3. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/.github/workflows/test.yml +6 -6
  4. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/PKG-INFO +1 -1
  5. panel_reactflow-0.3.1/docs/assets/screenshots/examples/advanced.png +0 -0
  6. panel_reactflow-0.3.1/docs/assets/screenshots/examples/custom_editor.png +0 -0
  7. panel_reactflow-0.3.1/docs/assets/screenshots/examples/edge_editors.png +0 -0
  8. panel_reactflow-0.3.1/docs/assets/screenshots/examples/node_edge_instances.png +0 -0
  9. panel_reactflow-0.3.1/docs/assets/screenshots/examples/schema_types.png +0 -0
  10. panel_reactflow-0.3.1/docs/assets/screenshots/examples/simple.png +0 -0
  11. panel_reactflow-0.3.1/docs/assets/screenshots/examples/threejs_viewer.png +0 -0
  12. panel_reactflow-0.3.1/docs/assets/screenshots/examples/threejs_viewer_instances.png +0 -0
  13. panel_reactflow-0.3.1/docs/examples/advanced.md +12 -0
  14. panel_reactflow-0.3.1/docs/examples/custom-editor.md +12 -0
  15. panel_reactflow-0.3.1/docs/examples/edge-editors.md +12 -0
  16. panel_reactflow-0.3.1/docs/examples/index.md +64 -0
  17. panel_reactflow-0.3.1/docs/examples/node-edge-instances.md +12 -0
  18. panel_reactflow-0.3.1/docs/examples/schema-types.md +12 -0
  19. panel_reactflow-0.3.1/docs/examples/simple.md +11 -0
  20. panel_reactflow-0.3.1/docs/examples/threejs-viewer-instances.md +12 -0
  21. panel_reactflow-0.3.1/docs/examples/threejs-viewer.md +12 -0
  22. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/docs/how-to/define-nodes-edges.md +110 -3
  23. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/docs/how-to/react-to-events.md +54 -2
  24. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/docs/index.md +4 -0
  25. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/docs/releases.md +29 -0
  26. panel_reactflow-0.3.1/examples/node_edge_instances.py +138 -0
  27. panel_reactflow-0.3.1/examples/threejs_viewer_instances.py +335 -0
  28. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/pixi.lock +306 -305
  29. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/src/panel_reactflow/__init__.py +4 -0
  30. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/src/panel_reactflow/base.py +756 -94
  31. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/tests/test_api.py +341 -1
  32. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/tests/test_core.py +40 -1
  33. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/zensical.toml +11 -1
  34. panel_reactflow-0.3.0rc0/docs/examples.md +0 -13
  35. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/.copier-answers.yml +0 -0
  36. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/.gitattributes +0 -0
  37. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/.github/CODEOWNERS +0 -0
  38. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/.github/dependabot.yml +0 -0
  39. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/.gitignore +0 -0
  40. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/.pre-commit-config.yaml +0 -0
  41. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/.prettierrc +0 -0
  42. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/LICENSE.txt +0 -0
  43. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/MANIFEST.in +0 -0
  44. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/README.md +0 -0
  45. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/docs/assets/logo.svg +0 -0
  46. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/docs/assets/screenshots/declare-types.png +0 -0
  47. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/docs/assets/screenshots/define-editors-edge.png +0 -0
  48. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/docs/assets/screenshots/define-editors-node.png +0 -0
  49. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/docs/assets/screenshots/define-nodes-edges.png +0 -0
  50. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/docs/assets/screenshots/embed-views-in-nodes.png +0 -0
  51. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/docs/assets/screenshots/quickstart.png +0 -0
  52. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/docs/assets/screenshots/react-to-events.png +0 -0
  53. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/docs/assets/screenshots/style-nodes-edges.png +0 -0
  54. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/docs/how-to/declare-types.md +0 -0
  55. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/docs/how-to/define-editors.md +0 -0
  56. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/docs/how-to/embed-views-in-nodes.md +0 -0
  57. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/docs/how-to/style-nodes-edges.md +0 -0
  58. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/docs/quickstart.md +0 -0
  59. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/docs/reference/panel_reactflow.md +0 -0
  60. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/examples/advanced.py +0 -0
  61. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/examples/custom_editor.py +0 -0
  62. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/examples/edge_editors.py +0 -0
  63. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/examples/schema_types.py +0 -0
  64. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/examples/simple.py +0 -0
  65. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/examples/threejs_viewer.py +0 -0
  66. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/hatch_build.py +0 -0
  67. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/pixi.toml +0 -0
  68. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/pyproject.toml +0 -0
  69. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/src/panel_reactflow/__version.py +0 -0
  70. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/src/panel_reactflow/dist/css/reactflow.css +0 -0
  71. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/src/panel_reactflow/dist/icons/gear.svg +0 -0
  72. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/src/panel_reactflow/dist/panel-reactflow.bundle.css +0 -0
  73. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/src/panel_reactflow/dist/panel-reactflow.bundle.js +0 -0
  74. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/src/panel_reactflow/models/reactflow.jsx +0 -0
  75. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/src/panel_reactflow/py.typed +0 -0
  76. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/src/panel_reactflow/schema.py +0 -0
  77. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/tests/__init__.py +0 -0
  78. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/tests/conftest.py +0 -0
  79. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/tests/ui/__init__.py +0 -0
  80. {panel_reactflow-0.3.0rc0 → panel_reactflow-0.3.1}/tests/ui/test_ui.py +0 -0
@@ -11,11 +11,11 @@ jobs:
11
11
  build:
12
12
  runs-on: ubuntu-latest
13
13
  steps:
14
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
14
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
15
15
  with:
16
16
  fetch-depth: 0
17
17
  - name: Set up pixi
18
- uses: prefix-dev/setup-pixi@ba3bb36eb2066252b2363392b7739741bb777659 # v0.8.1
18
+ uses: prefix-dev/setup-pixi@a0af7a228712d6121d37aba47adf55c1332c9c2e # v0.9.4
19
19
  with:
20
20
  environments: build
21
21
  - name: Build project
@@ -23,7 +23,7 @@ jobs:
23
23
  - name: Check package
24
24
  run: pixi run -e build check-wheel
25
25
  - name: Upload package
26
- uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
26
+ uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
27
27
  with:
28
28
  name: artifact
29
29
  path: dist/*
@@ -37,7 +37,7 @@ jobs:
37
37
  id-token: write
38
38
  environment: pypi
39
39
  steps:
40
- - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
40
+ - uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
41
41
  with:
42
42
  name: artifact
43
43
  path: dist
@@ -43,23 +43,23 @@ jobs:
43
43
  runs-on: ubuntu-latest
44
44
 
45
45
  steps:
46
- - uses: actions/checkout@v4
46
+ - uses: actions/checkout@v6
47
47
  with:
48
48
  fetch-depth: 0
49
49
  - name: Set up Pixi
50
- uses: prefix-dev/setup-pixi@ba3bb36eb2066252b2363392b7739741bb777659 # v0.8.1
50
+ uses: prefix-dev/setup-pixi@a0af7a228712d6121d37aba47adf55c1332c9c2e # v0.9.4
51
51
  with:
52
52
  environments: docs
53
53
  - name: Build documentation
54
54
  run: pixi run -e docs docs-build
55
- - uses: actions/upload-artifact@v4
55
+ - uses: actions/upload-artifact@v7
56
56
  if: always()
57
57
  with:
58
58
  name: docs
59
59
  if-no-files-found: error
60
60
  path: builtdocs
61
61
  - name: Upload artifact
62
- uses: actions/upload-pages-artifact@v3
62
+ uses: actions/upload-pages-artifact@v4
63
63
  with:
64
64
  path: ./builtdocs
65
65
 
@@ -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
@@ -20,7 +20,7 @@ jobs:
20
20
  code_change: ${{ steps.filter.outputs.code }}
21
21
  matrix: ${{ env.MATRIX }}
22
22
  steps:
23
- - uses: actions/checkout@v4
23
+ - uses: actions/checkout@v6
24
24
  if: github.event_name != 'pull_request'
25
25
  - name: Check for code changes
26
26
  uses: dorny/paths-filter@v3
@@ -80,9 +80,9 @@ jobs:
80
80
  needs: [setup, pixi_lock]
81
81
  runs-on: "ubuntu-latest"
82
82
  steps:
83
- - uses: actions/checkout@v5.0.0
83
+ - uses: actions/checkout@v6
84
84
  - name: Set up pixi
85
- uses: prefix-dev/setup-pixi@v0.9.2
85
+ uses: prefix-dev/setup-pixi@v0.9.4
86
86
  - uses: holoviz-dev/holoviz_tasks/pre-commit@v0
87
87
  - uses: pre-commit/action@v3.0.1
88
88
  if: needs.setup.outputs.img_change == 'true'
@@ -111,11 +111,11 @@ jobs:
111
111
  - windows-latest
112
112
  steps:
113
113
  - name: Checkout branch
114
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
114
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
115
115
  with:
116
116
  fetch-depth: 0
117
117
  - name: Set up pixi
118
- uses: prefix-dev/setup-pixi@ba3bb36eb2066252b2363392b7739741bb777659 # v0.8.1
118
+ uses: prefix-dev/setup-pixi@a0af7a228712d6121d37aba47adf55c1332c9c2e # v0.9.4
119
119
  with:
120
120
  environments: ${{ matrix.environment }}
121
121
  - name: Install repository
@@ -151,7 +151,7 @@ jobs:
151
151
  echo "[run]\nconcurrency = greenlet" > .uicoveragerc
152
152
  pixi run -e ${{ matrix.environment }} test-ui $COV --cov-config=.uicoveragerc $FAIL
153
153
  - name: Upload UI Screenshots
154
- uses: actions/upload-artifact@v5
154
+ uses: actions/upload-artifact@v7
155
155
  if: always()
156
156
  with:
157
157
  name: ui_screenshots_${{ runner.os }}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: panel-reactflow
3
- Version: 0.3.0rc0
3
+ Version: 0.3.1
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
@@ -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
+ ```
@@ -2,9 +2,9 @@
2
2
 
3
3
  Every graph in Panel-ReactFlow is built from two lists: **nodes** and
4
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.
5
+ connections between them. Nodes can be plain dictionaries, `NodeSpec`
6
+ objects, or `Node` instances, so you can choose between lightweight payloads
7
+ and object-oriented node classes.
8
8
 
9
9
  This guide covers how to create nodes and edges, use the helper dataclasses,
10
10
  and update data after the graph is live.
@@ -104,6 +104,40 @@ nodes = [
104
104
 
105
105
  ---
106
106
 
107
+ ## Define nodes as classes
108
+
109
+ Use `Node` when you want per-node Python state, event hooks, and optional
110
+ custom view/editor methods.
111
+
112
+ ```python
113
+ import panel as pn
114
+ from panel_reactflow import Node, ReactFlow
115
+
116
+
117
+ class JobNode(Node):
118
+ def __init__(self, **params):
119
+ super().__init__(type="job", data={"status": "idle"}, **params)
120
+
121
+ def __panel__(self):
122
+ return pn.pane.Markdown(f"**{self.label}**: {self.data.get('status')}")
123
+
124
+ def on_move(self, payload, flow):
125
+ print(f"{self.id} moved to {payload['position']}")
126
+
127
+
128
+ nodes = [
129
+ JobNode(id="j1", label="Fetch", position={"x": 0, "y": 0}),
130
+ JobNode(id="j2", label="Process", position={"x": 260, "y": 60}),
131
+ ]
132
+
133
+ flow = ReactFlow(nodes=nodes)
134
+ ```
135
+
136
+ `Node` instances stay as Python objects in `flow.nodes`; they are serialized
137
+ to dicts only when syncing to the frontend.
138
+
139
+ ---
140
+
107
141
  ## Define edges
108
142
 
109
143
  Edges link two nodes by their `id`. Use the top-level `label` for the
@@ -128,6 +162,79 @@ edges = [
128
162
 
129
163
  ---
130
164
 
165
+ ## Define edges as classes
166
+
167
+ Use `Edge` when you want object-oriented edge state and edge-specific hooks or
168
+ editor logic.
169
+
170
+ ```python
171
+ from panel_reactflow import Edge, ReactFlow
172
+
173
+
174
+ class FlowEdge(Edge):
175
+ def __init__(self, **params):
176
+ super().__init__(type="flow", data={"weight": 1.0}, **params)
177
+
178
+ def on_data_change(self, payload, flow):
179
+ print(f"{self.id} updated:", payload["patch"])
180
+
181
+
182
+ flow = ReactFlow(
183
+ nodes=[
184
+ {"id": "n1", "position": {"x": 0, "y": 0}, "data": {}},
185
+ {"id": "n2", "position": {"x": 260, "y": 60}, "data": {}},
186
+ ],
187
+ edges=[FlowEdge(id="e1", source="n1", target="n2")],
188
+ )
189
+ ```
190
+
191
+ `Edge` instances stay as Python objects in `flow.edges`; they are serialized
192
+ to dicts only when syncing to the frontend.
193
+
194
+ ---
195
+
196
+ ## Data <-> parameter sync on `Node` and `Edge`
197
+
198
+ For class-based nodes/edges, Panel-ReactFlow supports two-way synchronization
199
+ between `data` and declared parameters.
200
+
201
+ ### Which parameters are included?
202
+
203
+ Only subclass parameters with **explicit non-negative precedence**
204
+ (`precedence >= 0`) are treated as data fields.
205
+
206
+ ```python
207
+ import param
208
+ from panel_reactflow import Node
209
+
210
+
211
+ class TaskNode(Node):
212
+ status = param.Selector(default="idle", objects=["idle", "running", "done"], precedence=0)
213
+ retries = param.Integer(default=0, precedence=0)
214
+ _internal_state = param.String(default="x", precedence=-1)
215
+ ```
216
+
217
+ In this example:
218
+
219
+ - `status` and `retries` are included in `data`
220
+ - `_internal_state` is not included
221
+
222
+ ### Sync behavior
223
+
224
+ - **Parameter -> data**: updating `node.status` or `edge.weight` triggers an
225
+ automatic data patch to the graph and frontend.
226
+ - **Data -> parameter**: incoming graph patches/sync updates write values back
227
+ onto matching parameters.
228
+ - **Schema generation**: if no explicit type schema is provided, these
229
+ included parameters are used to generate a JSON schema for editors.
230
+
231
+ ### Editor implication
232
+
233
+ If your editor widgets are bound with `from_param(...)`, you usually do not
234
+ need manual `on_patch` watchers for those data parameters.
235
+
236
+ ---
237
+
131
238
  ## Use the NodeSpec / EdgeSpec helpers
132
239
 
133
240
  If you prefer a typed API, use the dataclass helpers. They validate fields
@@ -23,10 +23,10 @@ the `ReactFlow` instance as a second argument. You can also listen for
23
23
  | `node_deleted` | A node is removed. | `node_id` |
24
24
  | `node_moved` | A node is dragged to a new position. | `node_id`, `position` |
25
25
  | `node_clicked` | A node is clicked (single click). | `node_id` |
26
- | `node_data_changed` | `patch_node_data()` is called. | `node_id`, `patch` |
26
+ | `node_data_changed` | Node data is patched (via API, editor patch, or parameter-driven sync). | `node_id`, `patch` |
27
27
  | `edge_added` | An edge is created (UI connect or API). | `edge` |
28
28
  | `edge_deleted` | An edge is removed. | `edge_id` |
29
- | `edge_data_changed` | `patch_edge_data()` is called. | `edge_id`, `patch` |
29
+ | `edge_data_changed` | Edge data is patched (via API, editor patch, or parameter-driven sync). | `edge_id`, `patch` |
30
30
  | `selection_changed` | The active selection changes. | `nodes`, `edges` |
31
31
  | `sync` | A batch sync from the frontend. | *(varies)* |
32
32
 
@@ -57,6 +57,58 @@ pn.Column(log, flow).servable()
57
57
 
58
58
  ---
59
59
 
60
+ ## Handle events on `Node` classes
61
+
62
+ If you define nodes as `Node` subclasses, you can implement hooks directly on
63
+ the node instance:
64
+
65
+ ```python
66
+ from panel_reactflow import Node, ReactFlow
67
+
68
+
69
+ class TaskNode(Node):
70
+ def on_event(self, payload, flow):
71
+ print("any node event:", payload["type"])
72
+
73
+ def on_delete(self, payload, flow):
74
+ print("deleted:", self.id)
75
+
76
+
77
+ flow = ReactFlow(nodes=[TaskNode(id="t1", position={"x": 0, "y": 0}, data={})])
78
+ ```
79
+
80
+ Common hooks include `on_event` (wildcard), `on_add`, `on_move`, `on_click`,
81
+ `on_data_change`, and `on_delete`.
82
+
83
+ When a `Node` subclass parameter with `precedence >= 0` changes, it
84
+ automatically patches node data and will trigger `on_data_change`.
85
+
86
+ ---
87
+
88
+ ## Handle events on `Edge` classes
89
+
90
+ `Edge` subclasses can handle edge lifecycle and patch events directly:
91
+
92
+ ```python
93
+ from panel_reactflow import Edge, ReactFlow
94
+
95
+
96
+ class WeightedEdge(Edge):
97
+ def on_data_change(self, payload, flow):
98
+ print("edge patch:", payload["patch"])
99
+
100
+ def on_delete(self, payload, flow):
101
+ print("edge deleted:", self.id)
102
+ ```
103
+
104
+ Common edge hooks include `on_event`, `on_add`, `on_data_change`,
105
+ `on_selection_changed`, and `on_delete`.
106
+
107
+ Likewise, changing an `Edge` subclass data parameter (`precedence >= 0`)
108
+ triggers `on_data_change` through the same data patch pipeline.
109
+
110
+ ---
111
+
60
112
  ## Listen for all events
61
113
 
62
114
  Use the wildcard `"*"` to receive every event. This is useful for
@@ -66,6 +66,10 @@ flow.servable()
66
66
  - [Style Nodes & Edges](how-to/style-nodes-edges.md)
67
67
  - [React to Events](how-to/react-to-events.md)
68
68
 
69
+ ## Examples
70
+
71
+ - [Examples gallery](examples/index.md)
72
+
69
73
  ## Reference
70
74
 
71
75
  - [API reference](reference/panel_reactflow.md)
@@ -1,5 +1,34 @@
1
1
  # Release Notes
2
2
 
3
+ ## Version 0.3.0
4
+
5
+ This release focuses on core graph-model capabilities, callback ergonomics,
6
+ rendering/styling improvements, and major documentation expansion.
7
+
8
+ ### Highlights
9
+
10
+ - **Parameterized `Node`/`Edge` instances as first-class graph elements** —
11
+ `ReactFlow` now supports instance-based graph authoring with richer Python
12
+ object workflows, including improved serialization/sync behavior and expanded
13
+ API/core test coverage.
14
+ - **Event callback improvements** — `.on(...)` callbacks can now accept the
15
+ `ReactFlow` instance as a second argument and support async callbacks, making
16
+ app-level event handling significantly more flexible.
17
+ - **Rendering fixes for embedded views** — improved scaling and interaction
18
+ behavior when rendering figures inside nodes, including better handling of
19
+ drag/pan/scroll conflicts within embedded content.
20
+ - **Editor rendering robustness** — fixed node and edge editor rendering paths
21
+ so editors can render reliably even when no node `view` is defined.
22
+ - **Color mode and default node styling support** — added color-mode-aware
23
+ styling capabilities and refined baseline node CSS for better defaults out of
24
+ the box.
25
+ - **Expanded how-to documentation** — substantial updates to guides for
26
+ declaring types, defining nodes/edges, editors, embedding views, reacting to
27
+ events, and styling, with refreshed screenshots across the docs.
28
+ - **Examples overhaul in docs** — added an examples gallery with grid cards and
29
+ dedicated pages/screenshots for each example app, plus docs navigation
30
+ updates for easier discovery.
31
+
3
32
  ## Version 0.2.0
4
33
 
5
34
  This release focuses on stronger typed graph specs, better node-view handling,