Skip to content

feat: Accept drops onto the canvas and keep nodes mounted when node types change - #77

Merged
philippjfr merged 2 commits into
mainfrom
feat/canvas-drop
Sep 29, 2026
Merged

philippjfr merged 2 commits into
mainfrom
feat/canvas-drop

Conversation

@philippjfr

@philippjfr philippjfr commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Description

I added support for dropping data onto the canvas, so an app can build nodes from an external palette, and fixed nodes remounting whenever node_types changes.

  • drop_types lists the MIME types the canvas accepts. When data of one of them is dropped, the canvas emits a drop event with the matched drop_type, the dropped data (parsed from JSON when possible), the drop position in flow coordinates, and a target naming the node, and handle when there is one, under the pointer. A handler registered with flow.on("drop", ...) decides what to add and whether to wire it to that handle. Drops of other types, and all drops while editable is False, are ignored, so files or text dragged onto the canvas do nothing. Draggable panel_material_ui.MenuList items (feat: Add draggable MenuList items panel-material-ui#746) work as a source, and examples/drop_from_menu.py shows a palette whose items are added where they are dropped and connected when dropped on an input.
  • Any change to node_types rebuilt the component for every node type, so React remounted every node on the canvas and detached its embedded view, which could leave Bokeh plots blank. Apps that register node types lazily, e.g. panel-flowdash when a component is first used, hit this on every new type. Each type's component is now cached and reused until its own spec or the popup settings change.
import panel as pn
import panel_material_ui as pmui

from panel_reactflow import NodeSpec, NodeType, ReactFlow

pn.extension()

palette = pmui.MenuList(items=[{"label": "CSV file"}, {"label": "Database"}], draggable=True)
flow = ReactFlow(
    nodes=[NodeSpec(id="sink", type="sink", label="Sink", position={"x": 400, "y": 150}).to_dict()],
    node_types={"source": NodeType(type="source", inputs=[], outputs=["out"]), "sink": NodeType(type="sink", inputs=["in"])},
    drop_types=[palette.drag_type],
    max_zoom=1,
    sizing_mode="stretch_both",
    min_height=500,
)


def on_drop(payload, flow):
    item = palette.items[payload["data"]["path"][0]]
    node_id = f"source-{len(flow.nodes)}"
    flow.add_node(NodeSpec(id=node_id, type="source", label=item["label"], position=payload["position"]).to_dict())
    target = payload["target"]
    if target and target["direction"] == "input":
        flow.add_edge({"source": node_id, "sourceHandle": "out", "target": target["node_id"], "targetHandle": target["handle_id"]})


flow.on("drop", on_drop)
pmui.Row(palette, flow, sizing_mode="stretch_both").servable()

Dragging "CSV file" onto the canvas adds a node where it is dropped; dragging "Database" onto the Sink's input also connects it.

I added a Python test for the drop event payload and UI tests for drops on the pane, a node and a handle, for ignored types and non-editable canvases, a demo test that drags real MenuList items (skipped until panel-material-ui with draggable is installed), and a test that a node with a Bokeh view keeps its DOM element and canvas when a new node type is added, which fails without the cache. I documented the event in "React to Events" and added release notes. The Python tests (172), the UI suite (70 passed, 1 skipped) and pre-commit pass.

AI Disclosure

Tool & Model: Kilo Code + Claude Opus 5.5
Usage: Implemented the drop support, the remount fix and tests while wiring a component palette into panel-flowdash, and drafted this description; I reviewed the diff and ran the listed checks.

  • I have tested all AI-generated content in my PR.
  • I take responsibility for all AI-generated content in my PR.

Checklist

  • Tests added and are passing
  • Added documentation

@philippjfr
philippjfr merged commit fa0139f into main Sep 29, 2026
16 of 17 checks passed
@philippjfr
philippjfr deleted the feat/canvas-drop branch September 29, 2026 08:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant