diff --git a/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.jsx b/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.jsx index fbf88f78..ff489037 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.jsx +++ b/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.jsx @@ -17,16 +17,16 @@ import { sendLogGNB, sendLogTotalRecommend } from '../../actions/logActions'; import { getMyRecommandedKeyword } from '../../actions/myPageActions'; import { popPanel, updatePanel } from '../../actions/panelActions'; import { getSearch, resetSearch, searchMain } from '../../actions/searchActions'; -import { - showErrorToast, - showInfoToast, - showSearchErrorToast, - showSearchSuccessToast, - showSuccessToast, - showWarningToast, -} from '../../actions/toastActions'; +// import { +// showErrorToast, +// showInfoToast, +// showSearchErrorToast, +// showSearchSuccessToast, +// showSuccessToast, +// showWarningToast, +// } from '../../actions/toastActions'; import TBody from '../../components/TBody/TBody'; -import TInput, { ICONS, KINDS } from '../../components/TInput/TInput'; +import TInput, { ICONS, KINDS } from './TInput/TInput'; import TPanel from '../../components/TPanel/TPanel'; import TScroller from '../../components/TScroller/TScroller'; import TVerticalPagenator from '../../components/TVerticalPagenator/TVerticalPagenator'; @@ -101,6 +101,16 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt setInputFocus(false); }, [inputFocus]); + // TInput의 입력 모드 상태 (webOS 키보드가 뜨는지 여부) + const [isInputModeActive, setIsInputModeActive] = useState(false); + const handleInputModeChange = useCallback((isActive) => { + console.log( + '[SearchPanel] TInput 입력 모드:', + isActive ? '활성화 (키보드 표시)' : '비활성화 (키보드 숨김)' + ); + setIsInputModeActive(isActive); + }, []); + let searchQueryRef = usePrevious(searchQuery); let isOnTopRef = usePrevious(isOnTop); @@ -281,7 +291,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt ); // 검색 시작 알림 (선택사항) - dispatch(showSuccessToast(`"${query}" 검색 중...`, { duration: 2000 })); + // dispatch(showSuccessToast(`"${query}" 검색 중...`, { duration: 2000 })); } else { dispatch(resetSearch()); } @@ -473,10 +483,10 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt }, []); // 테스트용 Toast 핸들러들 - const handleTestToasts = useCallback(() => { - // 간단한 Toast 테스트 - dispatch(showSuccessToast('테스트 메시지입니다', { duration: 3000 })); - }, [dispatch]); + // const handleTestToasts = useCallback(() => { + // // 간단한 Toast 테스트 + // dispatch(showSuccessToast('테스트 메시지입니다', { duration: 3000 })); + // }, [dispatch]); // ProductCard 컴포넌트 const renderItem = useCallback( @@ -565,28 +575,36 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt spotlightId={SPOTLIGHT_IDS.SEARCH_INPUT_LAYER} >
- { - if (showVirtualKeyboard) { - handleSearchSubmit(searchQuery); - } else { - setShowVirtualKeyboard(true); - } - }} - onKeyDown={handleKeydown} - onKeyUp={cursorPosition} - spotlightId={SPOTLIGHT_IDS.SEARCH_INPUT_BOX} - forcedSpotlight="recent-keyword-0" - tabIndex={0} - spotlightBoxDisabled={true} - onFocus={_onFocus} - onBlur={_onBlur} - /> +
+ { + if (showVirtualKeyboard) { + handleSearchSubmit(searchQuery); + } else { + setShowVirtualKeyboard(true); + } + }} + onKeyDown={handleKeydown} + onKeyUp={cursorPosition} + spotlightId={SPOTLIGHT_IDS.SEARCH_INPUT_BOX} + forcedSpotlight="recent-keyword-0" + tabIndex={0} + spotlightBoxDisabled={true} + onFocus={_onFocus} + onBlur={_onBlur} + onInputModeChange={handleInputModeChange} + /> +
div { &:focus, diff --git a/com.twin.app.shoptime/src/views/SearchPanel/TInput/TInput.jsx b/com.twin.app.shoptime/src/views/SearchPanel/TInput/TInput.jsx new file mode 100644 index 00000000..ead6042a --- /dev/null +++ b/com.twin.app.shoptime/src/views/SearchPanel/TInput/TInput.jsx @@ -0,0 +1,151 @@ +import React, { useCallback, useState } from 'react'; + +import classNames from 'classnames'; + +import { InputField } from '@enact/sandstone/Input'; +import Spotlight from '@enact/spotlight'; +import Spottable from '@enact/spotlight/Spottable'; + +import useScrollReset from '../../../hooks/useScrollReset'; +import TIconButton from '../../../components/TIconButton/TIconButton'; +import css from './TInput.module.less'; + +const KINDS = { withIcon: 'withIcon' }; +const ICONS = { search: 'search' }; +const BORDER = { none: 'none' }; +const COLOR = { transparent: 'transparent' }; + +const Container = Spottable('div'); +export default function TInput({ + kind, + icon, + border, + color, + className, + spotlightDisabled, + spotlightBoxDisabled, + spotlightId, + disabled, + onKeyDown, + scrollTop, + onIconClick, + forcedSpotlight, + onFocus, + onBlur, + onInputModeChange, // 입력 모드 변경 콜백 + ...rest +}) { + const { handleScrollReset, handleStopScrolling } = useScrollReset(scrollTop); + + // 입력 가능 모드 상태 (webOS 키보드가 뜨는 상태) + const [isInputActive, setIsInputActive] = useState(false); + + const handleContainerClick = useCallback((e) => { + if (e.key === 'ArrrowLeft' || e.key === 'Left') { + Spotlight.focus('spotlight_search'); + } else { + Spotlight.focus('input-field-box'); + } + }, []); + + const handleButtonKeyDown = useCallback((e) => { + if (e.key === 'ArrowDown' || e.key === 'Down') { + Spotlight.move('down'); + } + + if (e.key === 'ArrowLeft' || e.key === 'Left') { + e.preventDefault(); + e.stopPropagation(); + Spotlight.focus('input-field-box'); + } + }, []); + + const handleBoxKeyDown = useCallback((e) => { + if (e.key === 'ArrowLeft' || e.key === 'Left') { + const currentElement = e.currentTarget; + const inputElement = currentElement.querySelector('input'); + + if (inputElement.value.length === 0) { + e.preventDefault(); + e.stopPropagation(); + Spotlight.focus('spotlight_search'); + } + } + }, []); + + //focus,blur 추가 + const _onFocus = useCallback(() => { + if (onFocus) { + onFocus(); + } + handleScrollReset(); + }, [onFocus]); + const _onBlur = useCallback(() => { + if (onBlur) { + onBlur(); + } + handleStopScrolling(); + }, [onBlur]); + + // onActivate: 내부 input에 실제로 포커스가 가서 입력 가능한 상태 (webOS 키보드가 뜨는 시점) + const _onActivate = useCallback(() => { + console.log('[TInput] Input 모드 활성화 - webOS 키보드 표시됨, isInputActive:', true); + setIsInputActive(true); + // 부모 컴포넌트에 모드 변경 알림 + if (onInputModeChange) { + onInputModeChange(true); + } + }, [onInputModeChange]); + + // onDeactivate: 내부 input에서 포커스가 빠져나감 (webOS 키보드가 사라지는 시점) + const _onDeactivate = useCallback(() => { + console.log('[TInput] Input 모드 비활성화 - webOS 키보드 숨김, isInputActive:', false); + setIsInputActive(false); + // 부모 컴포넌트에 모드 변경 알림 + if (onInputModeChange) { + onInputModeChange(false); + } + }, [onInputModeChange]); + + console.log('[TInput Render] isInputActive:', isInputActive); + + return ( + + + + {kind === 'withIcon' && ( + + )} + + ); +} + +export { BORDER, COLOR, ICONS, KINDS }; diff --git a/com.twin.app.shoptime/src/views/SearchPanel/TInput/TInput.module.less b/com.twin.app.shoptime/src/views/SearchPanel/TInput/TInput.module.less new file mode 100644 index 00000000..28fde3b4 --- /dev/null +++ b/com.twin.app.shoptime/src/views/SearchPanel/TInput/TInput.module.less @@ -0,0 +1,74 @@ +@import "../../../style/CommonStyle.module.less"; +@import "../../../style/utils.module.less"; + +.container { + width: fit-content; + height: fit-content; + position: relative; + + // 입력 가능 모드일 때 Container 스타일 + &.containerActive { + .input { + background-color: #ffff00 !important; // 노란색 배경 + } + } + + .input { + margin-right: 0; + margin-left: 0; + height: 100px !important; + padding: 20px 40px 20px 50px !important; + border-radius: 50px; + border: none !important; // SearchPanel의 wrapper에서 테두리 처리 + background-color: #fff !important; + width: 100% !important; + + &:focus { + box-shadow: none !important; // SearchPanel의 wrapper에서 포커스 처리 + border: none !important; + } + + > div { + display: none; + } + + > input { + font-family: @baseFont; + color: @COLOR_GRAY07 !important; + height: inherit !important; + line-height: inherit !important; + } + } + + // 입력 가능 모드 (webOS 키보드가 뜨는 상태) + // .input과 함께 사용되므로 더 구체적인 선택자 필요 + .input.inputActive { + background-color: #ffff00 !important; // 노란색 배경 + } + + .withIcon { + > div { + display: none; + } + } + + .search { + position: absolute; + background-repeat: no-repeat; + background-position: center top; + background-size: cover; + width: 40px; + height: 40px; + top: 50%; + right: 30px; + transform: translateY(-50%); + background-image: url("../../../../assets/images/searchpanel/ico_search_submit.png"); + + &:focus { + width: 42px; + height: 42px; + transform: translateY(-50%) scale(1.1); + background-position: center bottom; + } + } +} diff --git a/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx b/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx index dbfb05fd..f1306cff 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx +++ b/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx @@ -12,7 +12,7 @@ import Spottable from '@enact/spotlight/Spottable'; import micIcon from '../../../../assets/images/searchpanel/image-mic.png'; import { getShopperHouseSearch } from '../../../actions/searchActions'; import TFullPopup from '../../../components/TFullPopup/TFullPopup'; -import TInput, { ICONS, KINDS } from '../../../components/TInput/TInput'; +import TInput, { ICONS, KINDS } from '../TInput/TInput'; import { useWebSpeech } from '../../../hooks/useWebSpeech'; import VoiceListening from './modes/VoiceListening'; import VoiceNotRecognized from './modes/VoiceNotRecognized'; @@ -334,9 +334,9 @@ const VoiceInputOverlay = ({ setCurrentMode(mode); setVoiceInputMode(null); - // Overlay 내부로 포커스 이동 + // 마이크 버튼으로 포커스 이동 setTimeout(() => { - Spotlight.focus(OVERLAY_SPOTLIGHT_ID); + Spotlight.focus(MIC_SPOTLIGHT_ID); }, 100); } else { // Overlay가 닫힐 때 원래 포커스 복원 및 상태 초기화 diff --git a/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/modes/VoiceNotRecognized.module.less b/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/modes/VoiceNotRecognized.module.less index 8d107774..dd951fdf 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/modes/VoiceNotRecognized.module.less +++ b/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/modes/VoiceNotRecognized.module.less @@ -26,6 +26,7 @@ font-weight: 700; letter-spacing: -1px; color: #fff; + line-height: 1.2; } } }