feat(mobile): add touch gesture support for mobile devices

Added comprehensive touch support for mobile/tablet usage:

Touch Gestures Hook:
- Created useTouchGestures hook for pinch-to-zoom and two-finger pan
- Handles multi-touch events with distance calculation
- Integrated with canvas store for zoom and pan state
- Prevents default touch behaviors (pull-to-refresh, page scroll)

Features:
- Pinch-to-zoom: Two-finger pinch gesture for zoom in/out
- Two-finger pan: Pan canvas with two fingers
- Touch drawing: Single touch works for all drawing tools (pointer events already supported)
- Min/max zoom limits (0.1x - 32x)
- Smooth gesture handling with distance thresholds

UI Improvements:
- Added touch-action: none CSS to prevent default touch behaviors
- Added touch-none Tailwind class for better touch handling
- Canvas container properly handles touch events

Mobile Experience:
- Drawing tools work with single touch
- Zoom/pan gestures feel natural
- No interference with browser touch behaviors
- Optimized for tablets and touch-enabled devices

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-21 16:48:19 +01:00
parent 041db0aaff
commit 513b865b1f
2 changed files with 161 additions and 1 deletions

View File

@@ -10,6 +10,7 @@ import { getContext, drawGrid, drawCheckerboard } from '@/lib/canvas-utils';
import { renderText } from '@/lib/text-utils';
import { DrawCommand } from '@/core/commands';
import { getTool, preloadCommonTools } from '@/lib/tool-loader';
import { useTouchGestures } from '@/hooks/use-touch-gestures';
import type { BaseTool } from '@/tools';
import type { PointerState } from '@/types';
import { cn } from '@/lib/utils';
@@ -52,6 +53,12 @@ export function CanvasWithTools() {
pressure: 1,
});
// Touch gesture support for mobile
useTouchGestures(containerRef, {
minScale: 0.1,
maxScale: 32,
});
// Helper to get tool (lazy load if not in cache)
const getToolInstance = useCallback(async (toolKey: string): Promise<BaseTool | null> => {
if (toolsCache.current[toolKey]) {
@@ -418,9 +425,10 @@ export function CanvasWithTools() {
<div
ref={containerRef}
className={cn(
'relative h-full w-full overflow-hidden bg-canvas-bg',
'relative h-full w-full overflow-hidden bg-canvas-bg touch-none',
isPanning ? 'cursor-grabbing' : `cursor-${toolsCache.current[activeTool]?.getCursor(settings) || 'default'}`
)}
style={{ touchAction: 'none' }}
onWheel={handleWheel}
onPointerDown={handlePointerDown}
onPointerMove={handlePointerMove}