diff --git a/src/components/organisms/SearchableSelectionModal/SearchableSelectionModal.tsx b/src/components/organisms/SearchableSelectionModal/SearchableSelectionModal.tsx index 394625be..84ebddbb 100644 --- a/src/components/organisms/SearchableSelectionModal/SearchableSelectionModal.tsx +++ b/src/components/organisms/SearchableSelectionModal/SearchableSelectionModal.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useState, useCallback, useEffect } from 'react'; +import { useState, useCallback, useEffect, cloneElement, isValidElement } from 'react'; import { Search, X, Loader2 } from 'lucide-react'; import { @@ -156,11 +156,34 @@ export function SearchableSelectionModal(props: SearchableSelectionModalProps ); } - const itemElements = items.map((item) => ( -
handleItemClick(item)} className="cursor-pointer"> - {renderItem(item, isSelected(item))} -
- )); + const itemElements = items.map((item) => { + const key = keyExtractor(item); + const rendered = renderItem(item, isSelected(item)); + + // renderItem이 유효한 React 엘리먼트를 반환하면 key와 onClick을 직접 주입 (div 래핑 없이) + // 이렇게 하면 등 테이블 요소를
로 감싸는 HTML 유효성 에러를 방지 + if (isValidElement(rendered)) { + return cloneElement(rendered as React.ReactElement>, { + key, + onClick: (e: React.MouseEvent) => { + // 기존 onClick이 있으면 먼저 호출 + const existingOnClick = (rendered.props as Record)?.onClick; + if (typeof existingOnClick === 'function') { + (existingOnClick as (e: React.MouseEvent) => void)(e); + } + handleItemClick(item); + }, + className: `cursor-pointer ${(rendered.props as Record)?.className || ''}`.trim(), + }); + } + + // 일반 텍스트/fragment인 경우 기존 div 래핑 유지 + return ( +
handleItemClick(item)} className="cursor-pointer"> + {rendered} +
+ ); + }); if (listWrapper) { const selectState = mode === 'multiple'