[251030] feat: implement microphone button focus management with debouncing
마이크 버튼의 포커스 관리 및 음성 오버레이 로직 개선 🕐 커밋 시간: 2025. 10. 30. $(date +%H:%M:%S) 📊 변경 통계: • 총 파일: 1개 • 추가: +48줄 • 삭제: -5줄 📝 수정된 파일: ~ src/views/SearchPanel/SearchPanel.new.v2.jsx 🔧 주요 변경 내용: • isMicFocusable 상태 추가로 마이크 버튼 포커스 가능 여부 관리 • onFocusMic 콜백 핸들러 구현 (500ms 디바운싱 로직 포함) • 음성 오버레이 열기 로직을 재사용 가능한 openVoiceOverlay 함수로 추출 • SpottableMicButton 컴포넌트의 onFocus 이벤트 핸들러 활성화 (이전에는 주석 처리됨) • 언마운트 시 마이크 포커스 타이머 정리 로직 추가
This commit is contained in:
@@ -221,6 +221,9 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
// 🎯 HowAboutThese 포커스 관리 - 검색 입력 영역 포커스 감지용 상태
|
||||
const [searchInputFocused, setSearchInputFocused] = useState(false);
|
||||
|
||||
// 마이크 버튼 포커스 가능 여부 상태
|
||||
const [isMicFocusable, setIsMicFocusable] = useState(true);
|
||||
|
||||
// 🐛 [DEBUG] shopperHouseData 상태 변경 추적 (DEBUG_MODE가 true일 경우에만)
|
||||
useEffect(() => {
|
||||
if (DEBUG_MODE) {
|
||||
@@ -362,6 +365,8 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
setInputFocus(true);
|
||||
// 🎯 HowAboutThese 포커스 관리 - 검색 입력 영역 포커스 상태 설정
|
||||
setSearchInputFocused(true);
|
||||
// 마이크 버튼 포커스 가능하도록 설정
|
||||
setIsMicFocusable(true);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
@@ -382,6 +387,34 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
setSearchInputFocused(false);
|
||||
}, []);
|
||||
|
||||
// 마이크 버튼 포커스 핸들러
|
||||
const micFocusTimerRef = useRef(null);
|
||||
|
||||
const onFocusMic = useCallback(() => {
|
||||
// 이전 타이머 정리
|
||||
if (micFocusTimerRef.current) {
|
||||
clearTimeout(micFocusTimerRef.current);
|
||||
micFocusTimerRef.current = null;
|
||||
}
|
||||
|
||||
// isMicFocusable이 true인 경우에만 음성 오버레이 열기
|
||||
if (isMicFocusable) {
|
||||
openVoiceOverlay();
|
||||
|
||||
// 500ms 후에 isMicFocusable을 false로 설정
|
||||
micFocusTimerRef.current = setTimeout(() => {
|
||||
setIsMicFocusable(false);
|
||||
micFocusTimerRef.current = null;
|
||||
}, 500);
|
||||
} else {
|
||||
// isMicFocusable이 false인 경우 250ms 후에 TInputSimple으로 포커스 이동
|
||||
micFocusTimerRef.current = setTimeout(() => {
|
||||
Spotlight.focus(SPOTLIGHT_IDS.SEARCH_INPUT_BOX);
|
||||
micFocusTimerRef.current = null;
|
||||
}, 250);
|
||||
}
|
||||
}, [isMicFocusable, openVoiceOverlay]);
|
||||
|
||||
// 0hun: ✨ [Phase 3] showVirtualKeyboard 제거 (주석 처리된 VirtualKeyboardContainer와 함께 비활성화)
|
||||
const handleKeydown = useCallback(
|
||||
(e) => {
|
||||
@@ -547,16 +580,16 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* 0hun: Mic 아이콘 클릭 시 발생하는 이벤트, `isVoiceOverlayVisible`의 상태값을 `true`로 변경하는 함수
|
||||
* 0hun: 음성 입력 오버레이를 여는 공통 함수
|
||||
*/
|
||||
const onClickMic = useCallback(() => {
|
||||
const openVoiceOverlay = useCallback(() => {
|
||||
if (!isOnTopRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG_MODE) {
|
||||
console.log(
|
||||
'🖱️ [DEBUG][SearchPanel] onClickMic called, current isVoiceOverlayVisible:',
|
||||
'🎤 [DEBUG][SearchPanel] openVoiceOverlay called, current isVoiceOverlayVisible:',
|
||||
isVoiceOverlayVisible
|
||||
);
|
||||
}
|
||||
@@ -564,9 +597,15 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
setVoiceOverlayResponseText('');
|
||||
setIsVoiceOverlayBubbleSearch(false);
|
||||
setIsVoiceOverlayVisible(true);
|
||||
// setIsVoiceOverlayVisible((prev) => !prev);
|
||||
}, [isVoiceOverlayVisible]);
|
||||
|
||||
/**
|
||||
* 0hun: Mic 아이콘 클릭 시 발생하는 이벤트
|
||||
*/
|
||||
const onClickMic = useCallback(() => {
|
||||
openVoiceOverlay();
|
||||
}, [openVoiceOverlay]);
|
||||
|
||||
/**
|
||||
* 0hun: panel 뒤로가기 이벤트
|
||||
*/
|
||||
@@ -1748,6 +1787,10 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
clearTimeout(spotlightResumeTimerRef.current);
|
||||
spotlightResumeTimerRef.current = null;
|
||||
}
|
||||
if (micFocusTimerRef.current) {
|
||||
clearTimeout(micFocusTimerRef.current);
|
||||
micFocusTimerRef.current = null;
|
||||
}
|
||||
};
|
||||
}, [isOnTopRef]);
|
||||
|
||||
@@ -1855,7 +1898,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
<SpottableMicButton
|
||||
className={css.microphoneButton}
|
||||
onClick={onClickMic}
|
||||
// onFocus={onFocusMic}
|
||||
onFocus={onFocusMic}
|
||||
onKeyDown={handleMicKeyDown}
|
||||
spotlightId={SPOTLIGHT_IDS.MICROPHONE_BUTTON}
|
||||
// 🎯 [포커스 중첩 해결] SearchResultsContainer로 포커스 전달
|
||||
|
||||
Reference in New Issue
Block a user