"use client"; import { useCallback, useState } from "react"; import { useSortable } from "@dnd-kit/sortable"; import { CSS } from "@dnd-kit/utilities"; import { useTheme } from "next-themes"; import { MoreVertical, Trash2 } from "lucide-react"; import { cn } from "@/lib/utils"; import { Checkbox } from "@/components/ui/checkbox"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { getGroupColor } from "@/lib/colors"; import { useBoard } from "@/components/board/board-context"; import { NotesDialog } from "@/components/board/notes-dialog"; import { TodoCreatePopover } from "@/components/board/todo-create-popover"; import { TodoEditDialog } from "@/components/board/todo-edit-dialog"; import type { GroupDTO, TodoDTO } from "@/types/board"; export function GroupCard({ group }: { group: GroupDTO }) { const { toggleTodoDone, removeGroup } = useBoard(); const { resolvedTheme } = useTheme(); const [editingTodo, setEditingTodo] = useState(null); const { attributes, listeners, setNodeRef, setActivatorNodeRef, transform, transition, isDragging, } = useSortable({ id: group.id, data: { type: "group", categoryId: group.categoryId }, }); // dnd-kit's KeyboardSensor only treats Space/Enter as "pick up this card" // when the key event's target is this specific activator node -- but // that guard is skipped entirely if activatorNode.current is never set, // which left it preventDefault()-ing every Space/Enter keydown that // bubbled up through React's tree (not the DOM tree), including from // portaled Popover/Dialog content nested inside the card (the notes // editor, the "add to-do" popover). Wiring the same node as the // activator restores the target check. // // This must be memoized: a fresh function identity on every render makes // React detach+reattach the ref each time, which during a drag (many // re-renders as transform/isDragging change) resets dnd-kit's node // registration and broke drop detection entirely. const setCardRef = useCallback( (node: HTMLDivElement | null) => { setNodeRef(node); setActivatorNodeRef(node); }, [setNodeRef, setActivatorNodeRef] ); const color = getGroupColor(group.color); const borderColor = resolvedTheme === "dark" ? color.dark : color.light; return ( <>

{group.title}

} /> removeGroup(group.id, group.categoryId)} > Delete group
{editingTodo && ( !open && setEditingTodo(null)} /> )} ); }