feat: add delete button with confirmation to AnswerStubCard

Adds an inline delete flow to answer stub placeholder cards:
- Trash icon button (top-right, subtle) visible in idle state
- Click reveals "Delete this stub?" confirmation with Delete/Cancel
- Confirmed delete calls onDelete(nodeId) wired to handleDelete in TreeCanvas

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-02-18 02:26:13 -05:00
parent a4499e3cb3
commit e5f28a34d2
2 changed files with 42 additions and 7 deletions

View File

@@ -1,5 +1,5 @@
import { useState } from 'react'
import { HelpCircle, Zap, CheckCircle } from 'lucide-react'
import { HelpCircle, Zap, CheckCircle, Trash2 } from 'lucide-react'
import { cn } from '@/lib/utils'
import type { TreeStructure } from '@/types'
@@ -7,28 +7,62 @@ interface AnswerStubCardProps {
node: TreeStructure // type === 'answer'
fromOption?: string
onSelectType: (nodeId: string, type: 'decision' | 'action' | 'solution') => void
onDelete: (nodeId: string) => void
}
export function AnswerStubCard({ node, fromOption, onSelectType }: AnswerStubCardProps) {
export function AnswerStubCard({ node, fromOption, onSelectType, onDelete }: AnswerStubCardProps) {
const [picking, setPicking] = useState(false)
const [confirming, setConfirming] = useState(false)
const label = fromOption || node.title || 'Answer'
return (
<div
className={cn(
'min-w-[180px] max-w-[280px] rounded-xl border-2 border-dashed border-border bg-card/50',
'relative min-w-[180px] max-w-[280px] rounded-xl border-2 border-dashed border-border bg-card/50',
'transition-all duration-150',
!picking && 'cursor-pointer hover:border-primary/40 hover:bg-accent/30'
!picking && !confirming && 'cursor-pointer hover:border-primary/40 hover:bg-accent/30'
)}
onClick={() => !picking && setPicking(true)}
onClick={() => !picking && !confirming && setPicking(true)}
>
{/* Delete button — top-right corner */}
{!picking && !confirming && (
<button
type="button"
onClick={(e) => { e.stopPropagation(); setConfirming(true) }}
className="absolute top-1.5 right-1.5 rounded p-0.5 text-muted-foreground/40 hover:bg-red-500/10 hover:text-red-400 transition-colors"
title="Delete stub"
>
<Trash2 className="h-3 w-3" />
</button>
)}
{/* Label */}
<div className="px-3 pt-2.5 pb-1 text-sm font-heading font-medium text-foreground text-center">
{label}
</div>
{/* Prompt / type picker */}
{!picking ? (
{/* Confirm delete */}
{confirming ? (
<div className="px-2 pb-2.5 text-center space-y-1.5">
<p className="text-[10px] text-muted-foreground">Delete this stub?</p>
<div className="flex items-center justify-center gap-1.5">
<button
type="button"
onClick={(e) => { e.stopPropagation(); onDelete(node.id) }}
className="rounded-md px-2 py-1 text-[10px] font-label border border-red-500/30 bg-red-500/10 text-red-400 hover:bg-red-500/20"
>
Delete
</button>
<button
type="button"
onClick={(e) => { e.stopPropagation(); setConfirming(false) }}
className="rounded-md px-2 py-1 text-[10px] font-label border border-border text-muted-foreground hover:bg-accent"
>
Cancel
</button>
</div>
</div>
) : !picking ? (
<div className="pb-2.5 text-center text-[10px] text-muted-foreground font-label">
+ Choose Type
</div>

View File

@@ -503,6 +503,7 @@ export function TreeCanvas() {
node={node}
fromOption={optionLabel}
onSelectType={handleSelectAnswerType}
onDelete={handleDelete}
/>
) : (
<TreeCanvasNode