'use client'; import { useRef, useState } from 'react'; import { useRouter } from 'next/navigation'; import { useTranslations } from 'next-intl'; export default function InlineTitleEditor({ title, onRename, }: { title: string; onRename: (title: string) => Promise; }) { const router = useRouter(); const t = useTranslations('InlineTitle'); const [value, setValue] = useState(title); const [saved, setSaved] = useState(title); // Escape blurs the input; that blur must not save the canceled edit. const canceled = useRef(false); const save = async () => { if (canceled.current) { canceled.current = false; return; } const newTitle = value.trim(); if (!newTitle) { setValue(saved); return; } if (newTitle === saved) return; setValue(newTitle); try { if (await onRename(newTitle)) { setSaved(newTitle); router.refresh(); return; } } catch { // fall through: restore the saved title so the user can retry } setValue(saved); }; return ( setValue(e.target.value)} onBlur={save} onKeyDown={(e) => { if (e.key === 'Enter' && !e.nativeEvent.isComposing) e.currentTarget.blur(); if (e.key === 'Escape') { canceled.current = true; setValue(saved); e.currentTarget.blur(); } }} maxLength={255} aria-label={t('titleLabel')} placeholder={t('titlePlaceholder')} className="w-full min-w-0 bg-transparent rounded-[8px] -mx-2 px-2 font-[inherit] tracking-[inherit] leading-[inherit] outline-none hover:bg-muted/50 focus:bg-muted/50 focus:ring-2 focus:ring-ring transition-colors" /> ); }