fix(mobile): Symbol-Tap auf dem Handy zuverlässig – TouchBackend schluckte onClick (v1.5.2)

Ursache: react-dnd TouchBackend (delayTouchStart:150) unterdrückt auf Touch-
Geräten den onClick der Drag-Quelle → Tap-to-place löste auf dem Handy nie aus,
und echtes Touch-Drag über die MapLibre-Karte ist ohnehin unzuverlässig.

- DraggableSymbol erkennt Taps jetzt über echte Touch-Events (onTouchStart/End):
  kurzer, ortsfester Tipp (<12px, <600ms) = Auswahl → Karte antippen platziert
- preventDefault verhindert Doppel-Auslösung durch den synthetischen Klick
- onClick bleibt für Desktop/Maus erhalten

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Pepe Ziberi
2026-07-19 18:59:54 +02:00
parent 796ce53db3
commit 668476948e
2 changed files with 26 additions and 2 deletions

View File

@@ -1,6 +1,6 @@
'use client'
import { useState, useEffect } from 'react'
import { useState, useEffect, useRef } from 'react'
import { useDrag } from 'react-dnd'
import { getEmptyImage } from 'react-dnd-html5-backend'
import { Input } from '@/components/ui/input'
@@ -76,10 +76,34 @@ function DraggableSymbol({ symbol, canEdit, onSelect }: {
preview(getEmptyImage(), { captureDraggingState: true })
}, [preview])
// Touch-Tap eigenständig erkennen: der TouchBackend (react-dnd) schluckt auf
// dem Handy den onClick der Drag-Quelle. Ohne diesen Handler würde Tap-to-place
// auf Mobil gar nicht auslösen. Ein kurzer Tipp ohne Bewegung = Auswahl.
const touchStartRef = useRef<{ x: number; y: number; t: number } | null>(null)
const handleTouchStart = (e: React.TouchEvent) => {
const t = e.touches[0]
touchStartRef.current = { x: t.clientX, y: t.clientY, t: Date.now() }
}
const handleTouchEnd = (e: React.TouchEvent) => {
const start = touchStartRef.current
touchStartRef.current = null
if (!start || !canEdit || !onSelect) return
const t = e.changedTouches[0]
const moved = Math.hypot(t.clientX - start.x, t.clientY - start.y)
// Kurzer, ortsfester Tipp → als Auswahl werten (kein Drag)
if (moved < 12 && Date.now() - start.t < 600) {
e.preventDefault() // verhindert den synthetischen Klick (kein Doppel-Auslösen)
onSelect(symbol)
}
}
return (
<div
ref={drag as unknown as React.LegacyRef<HTMLDivElement>}
onClick={() => { if (canEdit && onSelect) onSelect(symbol) }}
onTouchStart={handleTouchStart}
onTouchEnd={handleTouchEnd}
className={`
flex flex-col items-center gap-1 p-1.5 md:p-2 lg:p-2.5 rounded-lg border-2 transition-all
border-transparent hover:border-border hover:bg-accent