fix: drag&drop events on folder headers with stopPropagation, separate root drop zone
This commit is contained in:
@@ -50,18 +50,39 @@ function TreeItem({
|
||||
const [expanded, setExpanded] = useState(true);
|
||||
const [isDragOver, setIsDragOver] = useState(false);
|
||||
const isRoot = node.folder === null;
|
||||
const folderId = node.folder?.id || null;
|
||||
|
||||
// Drop handler for this specific folder - stopPropagation so parent doesn't also fire
|
||||
const handleDrop = (e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsDragOver(false);
|
||||
onDropToFolder(folderId);
|
||||
};
|
||||
|
||||
const handleDragOver = (e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsDragOver(true);
|
||||
};
|
||||
|
||||
const handleDragLeave = (e: React.DragEvent) => {
|
||||
e.stopPropagation();
|
||||
// Only clear if leaving to a non-child element
|
||||
setIsDragOver(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
onDragOver={(e) => { e.preventDefault(); setIsDragOver(true); }}
|
||||
onDragLeave={() => setIsDragOver(false)}
|
||||
onDrop={(e) => { e.preventDefault(); setIsDragOver(false); onDropToFolder(node.folder?.id || null); }}
|
||||
>
|
||||
<div>
|
||||
{/* Folder header - this is the drop target */}
|
||||
{!isRoot && (
|
||||
<div
|
||||
onDragOver={handleDragOver}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={handleDrop}
|
||||
className={clsx(
|
||||
'group flex items-center gap-1 px-2 py-1.5 text-sm font-medium rounded-md cursor-pointer',
|
||||
isDragOver ? 'bg-primary-100 ring-1 ring-primary-300' : 'text-secondary-700 hover:bg-secondary-100'
|
||||
isDragOver ? 'bg-primary-100 ring-2 ring-primary-400' : 'text-secondary-700 hover:bg-secondary-100'
|
||||
)}
|
||||
style={{ paddingLeft: depth * 12 + 8 }}
|
||||
onClick={() => setExpanded(!expanded)}
|
||||
@@ -77,17 +98,19 @@ function TreeItem({
|
||||
<button onClick={(e) => { e.stopPropagation(); onDeleteFolder(node.folder!.id); }} className="opacity-0 group-hover:opacity-100 text-secondary-400 hover:text-red-600" title="Löschen">✕</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Sessions in this folder */}
|
||||
{(isRoot || expanded) && (
|
||||
<div>
|
||||
{node.sessions.map((session) => (
|
||||
<div
|
||||
key={session.id}
|
||||
draggable
|
||||
onDragStart={() => onDragSession(session.id)}
|
||||
onDragStart={(e) => { e.stopPropagation(); onDragSession(session.id); }}
|
||||
onClick={() => onSelectSession(session.id)}
|
||||
className={clsx(
|
||||
'group flex items-center gap-2 px-3 py-1.5 text-sm cursor-pointer rounded-md',
|
||||
'hover:bg-secondary-100 active:cursor-grabbing',
|
||||
'hover:bg-secondary-100',
|
||||
activeSessionId === session.id && 'bg-primary-100 text-primary-700'
|
||||
)}
|
||||
style={{ paddingLeft: depth * 12 + 24 }}
|
||||
@@ -101,6 +124,21 @@ function TreeItem({
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Root drop zone - only for root level, separate from sessions */}
|
||||
{isRoot && (
|
||||
<div
|
||||
onDragOver={handleDragOver}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={handleDrop}
|
||||
className={clsx(
|
||||
'min-h-[8px] rounded-md transition-colors',
|
||||
isDragOver && 'bg-primary-50 ring-1 ring-primary-300'
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Child folders */}
|
||||
{(isRoot || expanded) && node.children.map((child) => (
|
||||
<TreeItem
|
||||
key={child.folder!.id}
|
||||
|
||||
Reference in New Issue
Block a user