FE-1585: Define the canvas renderer contract and make React Flow its first implementation - #9508
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
fc8f5fe to
273ca42
Compare
PR SummaryMedium Risk Overview Adds a pluggable renderer layer: React Flow is relocated under Viewport helpers move to Reviewed by Cursor Bugbot for commit 80132cc. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
🟡 Changes recommended
Renderer coupling and incomplete component-port validation remain unresolved.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Refactors Petrinaut’s canvas behind renderer-neutral contracts, with React Flow as the first implementation and no intended user-facing changes.
Changes:
- Adds shared scene, interaction, viewport, renderer, and controller abstractions.
- Moves React Flow behind a renderer registry.
- Adds scene and viewport tests plus shared toolbar drag payloads.
File summaries
| File | Description |
|---|---|
libs/@hashintel/petrinaut/src/ui/views/shared/canvas-node-drag.ts |
Defines shared toolbar drag payloads. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/use-canvas-scene.ts |
Builds the active canvas scene. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/use-canvas-interactions.ts |
Centralizes interactions; component-port validation and interaction tests need improvement. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/sdcpn-view.tsx |
Measures the container and mounts the registered renderer. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/sdcpn-canvas.tsx |
Removes the monolithic canvas implementation. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/renderers/react-flow/react-flow-canvas/use-react-flow-elements.ts |
Maps scenes to React Flow elements; renderers still recompute scene state from editor context. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/renderers/react-flow/react-flow-canvas/use-react-flow-controller.ts |
Adapts React Flow viewport APIs. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/renderers/react-flow/react-flow-canvas/use-monaco-keyboard-isolation.ts |
Isolates Monaco keyboard events. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/renderers/react-flow/react-flow-canvas/use-apply-node-changes.ts |
Adapts React Flow node changes. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/renderers/react-flow/react-flow-canvas/transition-node.tsx |
Relocates transition rendering. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/renderers/react-flow/react-flow-canvas/react-flow-types.ts |
Defines renderer-specific element types. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/renderers/react-flow/react-flow-canvas/port-handles.ts |
Centralizes port-handle translation. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/renderers/react-flow/react-flow-canvas/place-state-tooltip.tsx |
Relocates place-state tooltip rendering. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/renderers/react-flow/react-flow-canvas/place-node.tsx |
Relocates place rendering. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/renderers/react-flow/react-flow-canvas/node-card.tsx |
Relocates shared node-card rendering. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/renderers/react-flow/react-flow-canvas/mini-map.tsx |
Adapts the minimap to scene node kinds. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/renderers/react-flow/react-flow-canvas/component-instance-node.tsx |
Uses centralized component port IDs. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/renderers/react-flow/react-flow-canvas/classic-transition-node.tsx |
Relocates classic transition rendering. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/renderers/react-flow/react-flow-canvas/classic-place-node.tsx |
Relocates classic place rendering. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/renderers/react-flow/react-flow-canvas/arc.tsx |
Adapts arcs to scene arc kinds. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/renderers/react-flow/react-flow-canvas.tsx |
Implements the React Flow renderer. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/reactflow-types.ts |
Removes legacy React Flow types. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/hooks/use-sdcpn-to-react-flow.ts |
Removes legacy element derivation. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/hooks/use-recenter-on-panel-open.ts |
Uses the renderer-neutral controller. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/hooks/use-apply-node-changes.ts |
Removes legacy change handling. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/components/viewport-controls.tsx |
Uses the canvas controller. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/canvas-viewport.ts |
Implements renderer-neutral viewport math. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/canvas-viewport.test.ts |
Tests fitting and recentering behavior. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/canvas-scene.ts |
Defines and derives canvas scenes. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/canvas-scene.test.ts |
Tests scene derivation. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/canvas-renderers.ts |
Registers available renderers. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/canvas-renderer.ts |
Defines renderer and controller contracts. |
libs/@hashintel/petrinaut/src/ui/views/Editor/components/BottomBar/toolbar-modes.tsx |
Writes shared drag payloads. |
libs/@hashintel/petrinaut/src/ui/petrinaut.tsx |
Removes the global xyflow stylesheet import. |
libs/@hashintel/petrinaut/src/ui/lib/viewport.test.ts |
Removes superseded viewport tests. |
Review details
Suppressed comments (1)
libs/@hashintel/petrinaut/src/ui/views/SDCPN/use-canvas-interactions.ts:115
useCanvasInteractionsnow defines the editing behavior shared by every renderer, but it has no tests; the SDCPN tests only cover scene and viewport derivation. Regressions in connection direction/port validation or snap-and-commit behavior would affect every implementation without being caught. Add hook tests for valid and invalid connections, snapped move/drop commits, and placement/read-only paths.
- Files reviewed: 35/35 changed files
- Comments generated: 2
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 273ca42. Configure here.
Review feedback read the replacement as reframing every net on first load. It does not: xyflow resolves a numeric padding to whole pixels a side and subtracts them from the container, which is the same fit as dividing the bounds by one plus the padding, to within that flooring.

Important
Refactor, no user-facing change.
Summary
Before this PR, the canvas view was one React Flow component. Node and arc derivation, selection, drag, connection and placement rules and the viewport lived in React Flow callbacks and hooks. Overlays such as the viewport controls called React Flow's API directly, so a second renderer would have to copy all of it.
Splits the canvas into a renderer-agnostic scene, shared interaction semantics and a renderer contract. React Flow becomes the first renderer behind that contract, moved under its own folder. Behaviour is unchanged.
Links
Changes
Contract
CanvasScenedescribes what a renderer drawsCanvasRendererprops and theCanvasControllercontextShared interactions
React Flow renderer
renderers/react-flow/petrinaut.tsxinto the rendererReview fixes
Test coverage
canvas-scene.test.ts:canvas-viewport.test.ts:fit-viewport-parity.test.ts:@hashintel/petrinautunit suite and storiesHow to test
mainmain