fix(canvas): three desktop interaction bugs
Mobile was working fine; desktop had a string of issues that surfaced together on the Pico Doom example after the simulator/wiring fixes. 1. Selection action bar appeared during simulation, intercepting button presses. handleComponentMouseDown unconditionally called e.stopPropagation() + setSelectedComponentId, so clicking a wokwi- pushbutton on a running canvas ate the mousedown — the button-press event never fired and the floating Rotate/Delete bar popped up on top of the button. Now: while running, the handler returns early so the event propagates to the underlying component and the canvas stays read-only. 2. The selection action bar was always visible on desktop. It was introduced as the primary delete UI for touch devices (no Delete key, no right-click), but it kept showing on mouse-and-keyboard too — covering pins and intercepting clicks. Now gated on isTouchDevice (already wired via useIsCoarsePointer) AND !running. Desktop users keep Delete key + right-click context menu for the same operations. 3. Left-click drag on the canvas background didn't pan. Pan was limited to middle/right click. Now left-click on empty canvas panning works too (component mousedowns stopPropagation so they still drag the component, not the camera). Wiring mode keeps left click for waypoint drops, so the pan only kicks in when not in wire mode and not in a property dialog. Matches Figma / Miro / draw.io convention. Build verified. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
fa224acb8d
commit
77a63ca10b
|
|
@ -1258,6 +1258,14 @@ export const SimulatorCanvas = ({ headerSlot }: SimulatorCanvasProps = {}) => {
|
|||
const handleComponentMouseDown = (componentId: string, e: React.MouseEvent) => {
|
||||
if (showPropertyDialog) return;
|
||||
|
||||
// While the simulator is running, the canvas is read-only. Don't
|
||||
// intercept the mousedown — let it propagate to the underlying
|
||||
// component (wokwi-pushbutton etc.) so it can fire button-press /
|
||||
// change events. Without this, every press on a button on the Pico
|
||||
// Doom canvas during a run was getting eaten by the drag/selection
|
||||
// handler.
|
||||
if (running) return;
|
||||
|
||||
e.stopPropagation();
|
||||
const component = components.find((c) => c.id === componentId);
|
||||
if (!component) return;
|
||||
|
|
@ -1543,7 +1551,19 @@ export const SimulatorCanvas = ({ headerSlot }: SimulatorCanvasProps = {}) => {
|
|||
|
||||
// Start panning on middle-click or right-click
|
||||
const handleCanvasMouseDown = (e: React.MouseEvent) => {
|
||||
if (e.button === 1 || e.button === 2) {
|
||||
// Middle / right click — always pan, regardless of context.
|
||||
// Left click — pan only when clicking ON THE BACKGROUND (the event
|
||||
// reaches the canvas because component mousedowns stopPropagation),
|
||||
// and only when not wiring (wire mode uses left click to drop
|
||||
// waypoints) or running a property dialog. Matches the diagram-editor
|
||||
// convention used in Figma / Miro / draw.io.
|
||||
const leftButton = e.button === 0;
|
||||
const middleOrRight = e.button === 1 || e.button === 2;
|
||||
const isPanGesture =
|
||||
middleOrRight ||
|
||||
(leftButton && !wireInProgress && !showPropertyDialog);
|
||||
|
||||
if (isPanGesture) {
|
||||
e.preventDefault();
|
||||
isPanningRef.current = true;
|
||||
panStartRef.current = {
|
||||
|
|
@ -2454,9 +2474,13 @@ export const SimulatorCanvas = ({ headerSlot }: SimulatorCanvasProps = {}) => {
|
|||
)}
|
||||
|
||||
{/* Floating action bar for the current selection — primary delete UI
|
||||
for touch devices (no Delete key, no right-click). Hidden while
|
||||
creating a wire so it doesn't fight the wire-mode banner. */}
|
||||
{!wireInProgress &&
|
||||
for touch devices (no Delete key, no right-click). Hidden:
|
||||
- while creating a wire (would fight the wire-mode banner)
|
||||
- on desktop (delete is bound to the Delete key, rotate is in
|
||||
the right-click menu — the floating bar covered nearby pins
|
||||
and intercepted clicks on buttons during simulation)
|
||||
- while the simulator is running (canvas is read-only). */}
|
||||
{!wireInProgress && isTouchDevice && !running &&
|
||||
(() => {
|
||||
if (selectedWireId) {
|
||||
const wire = wires.find((w) => w.id === selectedWireId);
|
||||
|
|
|
|||
Loading…
Reference in New Issue