feat(network): add pointer/hand mode toggle to diagram toolbar

- Header shows MousePointer2 (select) and Hand (pan) toggle buttons
- Select mode: drag on canvas draws a selection box (selectionOnDrag)
- Pan mode: drag on canvas pans the viewport (panOnDrag)
- Space held in either mode temporarily switches to pan (panActivationKeyCode)
- Keyboard shortcuts: V = select mode, H = pan mode
- Cursor changes to grab/grabbing in pan mode

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-04-14 00:38:51 +00:00
parent 4a12c9b37d
commit 684fb07e47
4 changed files with 65 additions and 4 deletions

View File

@@ -18,7 +18,7 @@ import { NetworkCanvas } from '@/components/network/NetworkCanvas'
import { ContextMenu, getNodeMenuActions, getCanvasMenuActions } from '@/components/network/ContextMenu'
import { useCanvasShortcuts } from '@/components/network/hooks/useCanvasShortcuts'
import { useDiagramCommands } from '@/components/network/hooks/useDiagramCommands'
import { DiagramHeader } from '@/components/network/DiagramHeader'
import { DiagramHeader, type InteractionMode } from '@/components/network/DiagramHeader'
import { DeviceToolbar } from '@/components/network/panels/DeviceToolbar'
import { PropertiesPanel } from '@/components/network/panels/PropertiesPanel'
import { AIAssistPanel } from '@/components/network/panels/AIAssistPanel'
@@ -69,6 +69,8 @@ function DiagramEditorInner() {
const [loading, setLoading] = useState(!!id)
const [isDragOver, setIsDragOver] = useState(false)
const [interactionMode, setInteractionMode] = useState<InteractionMode>('select')
const canvasRef = useRef<HTMLDivElement | null>(null)
const [contextMenu, setContextMenu] = useState<ContextMenuState>(null)
const [pendingDeleteNodeId, setPendingDeleteNodeId] = useState<string | null>(null)
@@ -154,6 +156,7 @@ function DiagramEditorInner() {
onUndo: undo,
onRedo: redo,
onNudge,
onSetMode: setInteractionMode,
})
const handleNodesChange: typeof onNodesChange = useCallback((changes) => {
@@ -675,6 +678,8 @@ function DiagramEditorInner() {
onRedo={redo}
canUndo={canUndo}
canRedo={canRedo}
interactionMode={interactionMode}
onModeChange={setInteractionMode}
/>
<div className="flex flex-1 min-h-0">
<DeviceToolbar deviceTypes={deviceTypes} onDeviceTypesChange={loadDeviceTypes} />
@@ -695,6 +700,7 @@ function DiagramEditorInner() {
onNodeContextMenu={handleNodeContextMenu}
onPaneContextMenu={handlePaneContextMenu}
onPaneClick={closeContextMenu}
interactionMode={interactionMode}
/>
{nodes.length === 0 && !loading && (
<CanvasEmptyPrompt onGenerate={handleAIGenerate} />