/** * 编辑输入框组件 * 实现编辑描述输入功能,支持键盘操作和动画效果 */ import React, { useState, useRef, useEffect, useCallback } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { Send, X, Loader2 } from 'lucide-react'; import { EditPoint, EditPointStatus } from './types'; interface EditInputProps { /** 编辑点数据 */ editPoint: EditPoint; /** 输入框位置 */ position: { x: number; y: number }; /** 是否显示 */ isVisible: boolean; /** 是否正在提交 */ isSubmitting?: boolean; /** 提交回调 */ onSubmit: (description: string) => void; /** 取消回调 */ onCancel: () => void; /** 输入框尺寸 */ size?: { width: number; height: number }; /** 占位符文本 */ placeholder?: string; } /** * 编辑输入框组件 */ export const EditInput: React.FC = ({ editPoint, position, isVisible, isSubmitting = false, onSubmit, onCancel, size = { width: 280, height: 120 }, placeholder = "Describe your edit request..." }) => { const [description, setDescription] = useState(editPoint.description || ''); const [isFocused, setIsFocused] = useState(false); const textareaRef = useRef(null); const containerRef = useRef(null); // 自动聚焦 useEffect(() => { if (isVisible && textareaRef.current) { // 延迟聚焦,等待动画完成 const timer = setTimeout(() => { textareaRef.current?.focus(); }, 300); return () => clearTimeout(timer); } }, [isVisible]); // 键盘事件处理 const handleKeyDown = useCallback((e: React.KeyboardEvent) => { if (e.key === 'Escape') { e.preventDefault(); onCancel(); } else if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) { e.preventDefault(); handleSubmit(); } }, [onCancel]); // 提交处理 const handleSubmit = useCallback(() => { const trimmedDescription = description.trim(); if (trimmedDescription && !isSubmitting) { onSubmit(trimmedDescription); } }, [description, isSubmitting, onSubmit]); // 点击外部关闭 useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (containerRef.current && !containerRef.current.contains(event.target as Node)) { // 如果有内容,自动提交;否则取消 if (description.trim()) { handleSubmit(); } else { onCancel(); } } }; if (isVisible) { document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); } }, [isVisible, description, handleSubmit, onCancel]); // 自动调整高度 const adjustHeight = useCallback(() => { if (textareaRef.current) { textareaRef.current.style.height = 'auto'; textareaRef.current.style.height = `${Math.min(textareaRef.current.scrollHeight, 120)}px`; } }, []); useEffect(() => { adjustHeight(); }, [description, adjustHeight]); return ( {isVisible && ( {/* 玻璃态背景容器 */}
{/* 头部 */}
Edit Request {Math.floor(editPoint.timestamp)}s
{/* 输入区域 */}