'use client'; import { useEffect, useRef, useState } from 'react'; import { Loader2, Pencil } from 'lucide-react'; import { cn } from '@/lib/utils'; interface InlineEditableTitleProps { value: string; onSave: (nextValue: string) => Promise | void; className?: string; inputClassName?: string; disabled?: boolean; } export function InlineEditableTitle({ value, onSave, className, inputClassName, disabled = false }: InlineEditableTitleProps) { const [editing, setEditing] = useState(false); const [draft, setDraft] = useState(value); const [saving, setSaving] = useState(false); const inputRef = useRef(null); useEffect(() => { if (!editing) setDraft(value); }, [editing, value]); useEffect(() => { if (editing) { inputRef.current?.focus(); inputRef.current?.select(); } }, [editing]); async function commit() { const trimmed = draft.trim(); if (!trimmed || trimmed === value) { setDraft(value); setEditing(false); return; } setSaving(true); try { await onSave(trimmed); setEditing(false); } finally { setSaving(false); } } if (editing) { return (
setDraft(event.target.value)} onBlur={() => void commit()} onKeyDown={(event) => { if (event.key === 'Enter') { event.preventDefault(); void commit(); } if (event.key === 'Escape') { setDraft(value); setEditing(false); } }} className={cn( 'w-full border-0 bg-transparent p-0 text-base font-semibold leading-tight text-[#1f2430] outline-none ring-0', inputClassName )} /> {saving ? : null}
); } return (
{!disabled ? ( ) : null}
); }