[251103] fix: VoiceResult Dropdown
🕐 커밋 시간: 2025. 11. 03. 18:18:30 📊 변경 통계: • 총 파일: 5개 • 추가: +128줄 • 삭제: -28줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/components/TDropDown/TDropDown.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.v2.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.v2.module.less ~ com.twin.app.shoptime/src/views/SearchPanel/components/TDropDown/TDropDown.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/components/TestDropDown/TestDropDown.jsx 🔧 주요 변경 내용: • UI 컴포넌트 아키텍처 개선 • 중간 규모 기능 개선
This commit is contained in:
@@ -19,6 +19,7 @@ export default memo(function TDropDown({
|
||||
scrollTop,
|
||||
selectedIndex,
|
||||
size,
|
||||
width,
|
||||
...rest
|
||||
}) {
|
||||
const { handleScrollReset, handleStopScrolling } = useScrollReset(scrollTop);
|
||||
@@ -36,7 +37,11 @@ export default memo(function TDropDown({
|
||||
}, [onClose]);
|
||||
|
||||
const _onChange = useCallback((event) => {
|
||||
console.log('[TDropDown] 🔥 _onChange 호출됨! event:', event);
|
||||
console.log('[TDropDown] event.selected:', event.selected);
|
||||
console.log('[TDropDown] onSelect 콜백 존재:', !!onSelect);
|
||||
if (onSelect) {
|
||||
console.log('[TDropDown] ✅ onSelect 콜백 실행 중...');
|
||||
onSelect({ selected: event.selected });
|
||||
}
|
||||
}, [onSelect]);
|
||||
@@ -57,6 +62,9 @@ export default memo(function TDropDown({
|
||||
onBlur={handleStopScrolling}
|
||||
onOpen={_onOpen}
|
||||
onClose={_onClose}
|
||||
style={width === 'small' ? { width: '240px', minWidth: '240px' } :
|
||||
width === 'medium' ? { width: '320px', minWidth: '320px' } :
|
||||
width === 'large' ? { width: '400px', minWidth: '400px' } : undefined}
|
||||
aria-disabled={countryCode && countryCode !== "US"}
|
||||
aria-label={children}
|
||||
{...rest}
|
||||
|
||||
@@ -14,7 +14,6 @@ import { hideShopperHouseError } from '../../actions/searchActions';
|
||||
import CustomImage from '../../components/CustomImage/CustomImage';
|
||||
import TButtonTab, { LIST_TYPE } from '../../components/TButtonTab/TButtonTab';
|
||||
import TDropDown from '../../components/TDropDown/TDropDown';
|
||||
import TestDropDown from './components/TestDropDown/TestDropDown';
|
||||
import TVirtualGridList from '../../components/TVirtualGridList/TVirtualGridList';
|
||||
import { panel_names } from '../../utils/Config';
|
||||
import { $L } from '../../utils/helperMethods';
|
||||
@@ -372,6 +371,17 @@ const SearchResultsNew = ({
|
||||
}
|
||||
}, [onSearchInputFocus, howAboutTheseMode]);
|
||||
|
||||
// 🎯 floatLayer에 드롭다운 스타일 클래스 추가 (MyOrders와 동일한 패턴)
|
||||
useEffect(() => {
|
||||
const c = document.getElementById("floatLayer");
|
||||
if (c) {
|
||||
c.classList.add("searchResults_dropdown");
|
||||
return () => {
|
||||
c.classList.remove("searchResults_dropdown");
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
|
||||
// HowAboutThese API 응답 받으면 RESPONSE → SMALL 모드로 전환
|
||||
useEffect(() => {
|
||||
console.log('[HowAboutThese] 🔍 2. useEffect 실행');
|
||||
@@ -447,7 +457,7 @@ const SearchResultsNew = ({
|
||||
const displayedData = useMemo(() => {
|
||||
if (!currentData) return [];
|
||||
return currentData.slice(0, visibleCount);
|
||||
}, [currentData, visibleCount]);
|
||||
}, [currentData, visibleCount, dropDownTab]);
|
||||
|
||||
// 더 불러올 데이터가 있는지 확인
|
||||
const hasMore = currentData && visibleCount < currentData.length;
|
||||
@@ -513,6 +523,13 @@ const SearchResultsNew = ({
|
||||
[]
|
||||
);
|
||||
|
||||
// 🎯 탭 영역을 Spotlight 컨테이너로 감싸기 (MyOrders와 동일한 패턴)
|
||||
// 드롭다운이 열렸을 때 포커스가 아래로 튕겨나가지 않도록 함
|
||||
const TabContainer = useMemo(
|
||||
() => SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div'),
|
||||
[]
|
||||
);
|
||||
|
||||
// ❌ [251026] DEPRECATED: 탭 키다운 핸들러 - Spotlight 속성으로 대체됨
|
||||
// Spotlight의 data-spotlight-up 속성으로 처리하도록 변경
|
||||
// 기존 코드 보존 (향후 필요시 참고용)
|
||||
@@ -739,7 +756,7 @@ const SearchResultsNew = ({
|
||||
|
||||
{/* 메인 컨텐츠 영역 */}
|
||||
<div className={css.itemBox}>
|
||||
<div className={css.tabContainer}>
|
||||
<TabContainer className={css.tabContainer}>
|
||||
<TButtonTab
|
||||
contents={buttonTabList}
|
||||
onItemClick={handleButtonTabClick}
|
||||
@@ -751,26 +768,21 @@ const SearchResultsNew = ({
|
||||
|
||||
{/* 필터링 dropdown - ShopperHouse 데이터가 있을 때 정렬 옵션 표시 */}
|
||||
{tab === 0 && hasShopperHouseItems && (
|
||||
<>
|
||||
<TDropDown
|
||||
className={classNames(
|
||||
css.dropdown,
|
||||
styleChange === true ? css.categoryDropdown : null
|
||||
)}
|
||||
onOpen={handleStyle}
|
||||
onClose={handleStyleOut}
|
||||
onSelect={handleSelectFilter}
|
||||
selectedIndex={dropDownTab}
|
||||
width="small"
|
||||
>
|
||||
{filterMethods}
|
||||
</TDropDown>
|
||||
|
||||
{/* TestDropDown - 테스트용 드롭다운 */}
|
||||
<TestDropDown className={css.dropdown} />
|
||||
</>
|
||||
<TDropDown
|
||||
className={classNames(
|
||||
css.dropdown,
|
||||
styleChange === true ? css.categoryDropdown : null
|
||||
)}
|
||||
onOpen={handleStyle}
|
||||
onClose={handleStyleOut}
|
||||
onSelect={handleSelectFilter}
|
||||
selectedIndex={dropDownTab}
|
||||
width="small"
|
||||
>
|
||||
{filterMethods}
|
||||
</TDropDown>
|
||||
)}
|
||||
</div>
|
||||
</TabContainer>
|
||||
|
||||
{/* 아이템/쇼 컨텐츠 */}
|
||||
{tab === 0 && <ItemCard itemInfo={displayedData} />}
|
||||
|
||||
@@ -395,6 +395,79 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// floatLayer 드롭다운 스타일 관리 (MyOrders와 동일한 패턴)
|
||||
// 6개 항목을 모두 표시 (각 항목 약 63px + 여백)
|
||||
[class="searchResults_dropdown"] {
|
||||
> div > div[id] > div:nth-child(2) {
|
||||
-webkit-filter: none !important;
|
||||
filter: none !important;
|
||||
> div:nth-child(1) {
|
||||
height: 380px !important;
|
||||
width: 270px !important;
|
||||
margin-top: 0 !important;
|
||||
border-radius: 0 0 6px 6px !important;
|
||||
background-color: #f5f5f5 !important;
|
||||
overflow-y: auto !important;
|
||||
> div {
|
||||
width: 270px !important;
|
||||
height: auto !important;
|
||||
border-radius: 0 !important;
|
||||
padding-top: 0 !important;
|
||||
color: #333 !important;
|
||||
background-color: white !important;
|
||||
> div {
|
||||
color: #333 !important;
|
||||
background-color: white !important;
|
||||
> div {
|
||||
color: #333 !important;
|
||||
background-color: white !important;
|
||||
> div {
|
||||
padding: 0 !important;
|
||||
color: #333 !important;
|
||||
background-color: white !important;
|
||||
&:first-child {
|
||||
> div:nth-child(1) {
|
||||
border-radius: 6px 6px 0 0 !important;
|
||||
overflow: hidden;
|
||||
&:focus {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
> div:first-child {
|
||||
will-change: unset !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
&:last-child {
|
||||
> div:nth-child(1) {
|
||||
border-radius: 0 0 6px 6px !important;
|
||||
overflow: hidden;
|
||||
&:focus {
|
||||
border-radius: 0 0 6px 6px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
> div:nth-child(1) {
|
||||
height: 63px !important;
|
||||
padding: 20px 19px !important;
|
||||
background-color: white !important;
|
||||
color: #333 !important;
|
||||
&:focus {
|
||||
background-color: #c70850 !important;
|
||||
color: white !important;
|
||||
box-shadow: 0 0 22px 0 rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.searchBox {
|
||||
.buttonContainer {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
||||
@@ -19,6 +19,7 @@ export default memo(function TDropDown({
|
||||
scrollTop,
|
||||
selectedIndex,
|
||||
size,
|
||||
width,
|
||||
...rest
|
||||
}) {
|
||||
const { handleScrollReset, handleStopScrolling } = useScrollReset(scrollTop);
|
||||
@@ -57,6 +58,9 @@ export default memo(function TDropDown({
|
||||
onBlur={handleStopScrolling}
|
||||
onOpen={_onOpen}
|
||||
onClose={_onClose}
|
||||
style={width === 'small' ? { width: '240px', minWidth: '240px' } :
|
||||
width === 'medium' ? { width: '320px', minWidth: '320px' } :
|
||||
width === 'large' ? { width: '400px', minWidth: '400px' } : undefined}
|
||||
aria-disabled={countryCode && countryCode !== "US"}
|
||||
aria-label={children}
|
||||
{...rest}
|
||||
|
||||
@@ -6,13 +6,15 @@ const TestDropDown = ({ className }) => {
|
||||
const testOptions = ['Option 1', 'Option 2', 'Option 3'];
|
||||
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||
|
||||
const handleSelect = useCallback((selected) => {
|
||||
const newSelectedIndex = selected.selected;
|
||||
console.log('[TestDropDown] Selected:', newSelectedIndex, testOptions[newSelectedIndex]);
|
||||
setSelectedIndex(newSelectedIndex);
|
||||
}, [testOptions]);
|
||||
const handleSelect = useCallback(({ selected }) => {
|
||||
console.log('[TestDropDown] 🎯 선택됨 - index:', selected, 'text:', testOptions[selected]);
|
||||
console.log('[TestDropDown] 이전 selectedIndex:', selectedIndex, '→ 새로운:', selected);
|
||||
setSelectedIndex(selected);
|
||||
}, [testOptions, selectedIndex]);
|
||||
|
||||
console.log('[TestDropDown] Rendering with selectedIndex:', selectedIndex);
|
||||
console.log('[TestDropDown] 렌더링 - selectedIndex:', selectedIndex);
|
||||
console.log('[TestDropDown] testOptions:', testOptions);
|
||||
console.log('[TestDropDown] children으로 전달될 값:', testOptions);
|
||||
|
||||
return (
|
||||
<TDropDown
|
||||
@@ -20,6 +22,7 @@ const TestDropDown = ({ className }) => {
|
||||
onSelect={handleSelect}
|
||||
selectedIndex={selectedIndex}
|
||||
size="small"
|
||||
direction="above"
|
||||
>
|
||||
{testOptions}
|
||||
</TDropDown>
|
||||
|
||||
Reference in New Issue
Block a user