From 0b48e43eb4c6857b40a36e7f1eba037204a7300c Mon Sep 17 00:00:00 2001 From: optrader Date: Fri, 17 Oct 2025 12:33:31 +0900 Subject: [PATCH] [251017] fix: SearchPanel TInput MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ๐Ÿ• ์ปค๋ฐ‹ ์‹œ๊ฐ„: 2025. 10. 17. 12:33:29 ๐Ÿ“Š ๋ณ€๊ฒฝ ํ†ต๊ณ„: โ€ข ์ด ํŒŒ์ผ: 6๊ฐœ โ€ข ์ถ”๊ฐ€: +75์ค„ โ€ข ์‚ญ์ œ: -48์ค„ ๐Ÿ“ ์ถ”๊ฐ€๋œ ํŒŒ์ผ: + com.twin.app.shoptime/src/views/SearchPanel/TInput/TInput.jsx + com.twin.app.shoptime/src/views/SearchPanel/TInput/TInput.module.less ๐Ÿ“ ์ˆ˜์ •๋œ ํŒŒ์ผ: ~ com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.module.less ~ com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/modes/VoiceNotRecognized.module.less ๐Ÿ”ง ํ•จ์ˆ˜ ๋ณ€๊ฒฝ ๋‚ด์šฉ: ๐Ÿ“„ com.twin.app.shoptime/src/views/SearchPanel/TInput/TInput.module.less (unknown): โœ… Added: translateY() --- .../src/views/SearchPanel/SearchPanel.new.jsx | 90 ++++++----- .../SearchPanel/SearchPanel.new.module.less | 34 ++-- .../src/views/SearchPanel/TInput/TInput.jsx | 151 ++++++++++++++++++ .../SearchPanel/TInput/TInput.module.less | 74 +++++++++ .../VoiceInputOverlay/VoiceInputOverlay.jsx | 6 +- .../modes/VoiceNotRecognized.module.less | 1 + 6 files changed, 308 insertions(+), 48 deletions(-) create mode 100644 com.twin.app.shoptime/src/views/SearchPanel/TInput/TInput.jsx create mode 100644 com.twin.app.shoptime/src/views/SearchPanel/TInput/TInput.module.less 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; } } }