/** * 사전 단어 항목 컴포넌트 * - 사전 관리 페이지의 단어 테이블 행 */ import { useState, useEffect, useRef } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { Trash2, ChevronDown } from 'lucide-react'; /** * 품사 태그 옵션 */ export const POS_TAGS = [ { value: 'NNP', label: '고유명사 (NNP)', description: '사람, 그룹, 프로그램 이름 등', examples: '프로미스나인, 송하영, 뮤직뱅크', }, { value: 'NNG', label: '일반명사 (NNG)', description: '일반적인 명사', examples: '직캠, 팬미팅, 콘서트', }, { value: 'SL', label: '외국어 (SL)', description: '영어 등 외국어 단어', examples: 'fromis_9, YouTube, fromm', }, ]; /** * 단어 항목 컴포넌트 * @param {Object} props * @param {string} props.id - 단어 고유 ID * @param {string} props.word - 단어 * @param {string} props.pos - 품사 태그 * @param {number} props.index - 목록 인덱스 * @param {Function} props.onUpdate - 수정 핸들러 (id, word, pos) * @param {Function} props.onDelete - 삭제 핸들러 () */ function WordItem({ id, word, pos, index, onUpdate, onDelete }) { const [isEditing, setIsEditing] = useState(false); const [editWord, setEditWord] = useState(word); const [editPos, setEditPos] = useState(pos); const [showPosDropdown, setShowPosDropdown] = useState(false); const dropdownRef = useRef(null); // 외부 클릭 시 드롭다운 닫기 useEffect(() => { const handleClickOutside = (event) => { if (dropdownRef.current && !dropdownRef.current.contains(event.target)) { setShowPosDropdown(false); } }; if (showPosDropdown) { document.addEventListener('mousedown', handleClickOutside); } return () => document.removeEventListener('mousedown', handleClickOutside); }, [showPosDropdown]); const handleSave = () => { if (editWord.trim() && (editWord.trim() !== word || editPos !== pos)) { onUpdate(id, editWord.trim(), editPos); } setIsEditing(false); }; const handleKeyDown = (e) => { if (e.key === 'Enter') { handleSave(); } else if (e.key === 'Escape') { setEditWord(word); setEditPos(pos); setIsEditing(false); } }; return ( {index + 1} {isEditing ? ( setEditWord(e.target.value)} onKeyDown={handleKeyDown} onBlur={handleSave} autoFocus className="w-full px-3 py-1.5 border border-primary rounded-lg focus:outline-none focus:ring-2 focus:ring-primary/20" /> ) : ( setIsEditing(true)} className="cursor-pointer hover:text-primary transition-colors font-medium" > {word} )}
{showPosDropdown && ( {POS_TAGS.map((tag) => ( ))} )}
); } export default WordItem;