[251012] fix: PlayerPanel,TabContainerV2 focus - 1

🕐 커밋 시간: 2025. 10. 12. 18:13:40

📊 변경 통계:
  • 총 파일: 7개
  • 추가: +169줄
  • 삭제: -25줄

📝 수정된 파일:
  ~ com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js
  ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayContents.jsx
  ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx
  ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/LiveChannelContents.jsx
  ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/ShopNowContents.jsx
  ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/ShopNowButton.jsx
  ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx

🔧 함수 변경 내용:
  📄 com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayContents.jsx (javascript):
     Added: onSpotlightMoveBelowTab()
  📄 com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/ShopNowContents.jsx (javascript):
    🔄 Modified: SpotlightContainerDecorator()

🔧 주요 변경 내용:
  • UI 컴포넌트 아키텍처 개선
This commit is contained in:
2025-10-12 18:13:42 +09:00
parent 05a1629fc9
commit aa811980dd
7 changed files with 243 additions and 129 deletions

View File

@@ -710,6 +710,10 @@ const VideoPlayerBase = class extends React.Component {
reactPlayerConfig: PropTypes.any, //for ReactPlayer
qrCurrentItem: PropTypes.any,
modalScale: PropTypes.number,
setBelowContentsVisible: PropTypes.func,
belowContentsVisible: PropTypes.bool,
tabContainerVersion: PropTypes.number,
tabIndexV2: PropTypes.number,
};
static contextType = FloatingLayerContext;
@@ -854,6 +858,29 @@ const VideoPlayerBase = class extends React.Component {
this.showControls();
}
}
// TabContainerV2와 mediaControls 동기화
if (
this.props.tabContainerVersion === 2 &&
this.props.belowContentsVisible !== undefined &&
prevProps.belowContentsVisible !== this.props.belowContentsVisible
) {
console.log('[VideoPlayer] belowContentsVisible 변경 감지:', {
prev: prevProps.belowContentsVisible,
current: this.props.belowContentsVisible,
mediaControlsVisible: this.state.mediaControlsVisible,
});
if (this.props.belowContentsVisible && !this.state.mediaControlsVisible) {
// TabContainerV2가 표시될 때 controls도 표시
console.log('[VideoPlayer] TabContainerV2 표시 - controls 강제 표시');
this.showControls();
} else if (!this.props.belowContentsVisible && this.state.mediaControlsVisible) {
// TabContainerV2가 숨겨질 때 controls도 숨김
console.log('[VideoPlayer] TabContainerV2 숨김 - controls 숨김');
this.hideControls();
}
}
if (
(!this.state.mediaControlsVisible &&
prevState.mediaControlsVisible !== this.state.mediaControlsVisible) ||
@@ -1016,6 +1043,13 @@ const VideoPlayerBase = class extends React.Component {
// If this.state.more is used as a reference for when this function should fire, timing for
// detection of when "more" is pressed vs when the state is updated is mismatched. Using an
// instance variable that's only set and used for this express purpose seems cleanest.
// TabContainerV2가 표시 중이면 자동으로 닫지 않음
if (this.props.tabContainerVersion === 2 && this.props.belowContentsVisible) {
console.log('[VideoPlayer] TabContainerV2 표시 중 - autoClose 비활성화');
return;
}
if (this.props.autoCloseTimeout && !this.props.sideContentsVisible) {
this.autoCloseJob.startAfter(this.props.autoCloseTimeout);
}
@@ -1947,10 +1981,13 @@ const VideoPlayerBase = class extends React.Component {
return;
}
// TabContainerV2 토글
if (this.props.setBelowContentsVisible && this.props.belowContentsVisible !== undefined) {
console.log('[VideoPlayer] belowContentsVisible 토글:', !this.props.belowContentsVisible);
this.props.setBelowContentsVisible(!this.props.belowContentsVisible);
// tabContainerVersion === 2일 때 belowContentsVisible도 함께 토글
if (this.props.tabContainerVersion === 2 && this.props.setBelowContentsVisible) {
const willShowControls = !this.state.mediaControlsVisible;
console.log('[VideoPlayer] 클릭 - 상태 동기화 토글:', willShowControls);
// belowContentsVisible을 먼저 변경 (componentDidUpdate에서 mediaControls 동기화됨)
this.props.setBelowContentsVisible(willShowControls);
}
this.toggleControls();
@@ -2152,6 +2189,8 @@ const VideoPlayerBase = class extends React.Component {
isYoutube,
sideContentsVisible,
setSideContentsVisible,
belowContentsVisible,
tabContainerVersion,
disclaimer,
liveTotalTime,
currentLiveTimeSeconds,
@@ -2196,6 +2235,10 @@ const VideoPlayerBase = class extends React.Component {
delete mediaProps.thumbnailUnavailable;
delete mediaProps.titleHideDelay;
delete mediaProps.videoPath;
delete mediaProps.setBelowContentsVisible;
delete mediaProps.belowContentsVisible;
delete mediaProps.tabContainerVersion;
delete mediaProps.tabIndexV2;
mediaProps.autoPlay = !noAutoPlay;
mediaProps.className = type !== 'MEDIA' ? css.video : css.media;
@@ -2393,6 +2436,9 @@ const VideoPlayerBase = class extends React.Component {
setIsSubtitleActive={setIsSubtitleActive}
sideContentsVisible={sideContentsVisible}
setSideContentsVisible={setSideContentsVisible}
belowContentsVisible={belowContentsVisible}
tabContainerVersion={tabContainerVersion}
tabIndexV2={this.props.tabIndexV2}
videoVerticalVisible={videoVerticalVisible}
handleIndicatorUpClick={handleIndicatorUpClick}
handleIndicatorDownClick={handleIndicatorDownClick}

View File

@@ -1,27 +1,24 @@
import React, { useCallback, useEffect, useMemo, useRef } from "react";
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
import classNames from "classnames";
import { useDispatch, useSelector } from "react-redux";
import classNames from 'classnames';
import { useDispatch, useSelector } from 'react-redux';
import Spotlight from "@enact/spotlight";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import Spottable from "@enact/spotlight/Spottable";
import Marquee from "@enact/ui/Marquee";
import Spotlight from '@enact/spotlight';
import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator';
import Spottable from '@enact/spotlight/Spottable';
import Marquee from '@enact/ui/Marquee';
import defaultLogoImg from "../../../../assets/images/ic-tab-partners-default@3x.png";
import { setShowPopup } from "../../../actions/commonActions";
import CustomImage from "../../../components/CustomImage/CustomImage";
import { ACTIVE_POPUP } from "../../../utils/Config";
import { SpotlightIds } from "../../../utils/SpotlightIds";
import PlayerTabButton from "../PlayerTabContents/TabButton/PlayerTabButton";
import css from "./PlayerOverlayContents.module.less";
import defaultLogoImg from '../../../../assets/images/ic-tab-partners-default@3x.png';
import { setShowPopup } from '../../../actions/commonActions';
import CustomImage from '../../../components/CustomImage/CustomImage';
import { ACTIVE_POPUP } from '../../../utils/Config';
import { SpotlightIds } from '../../../utils/SpotlightIds';
import PlayerTabButton from '../PlayerTabContents/TabButton/PlayerTabButton';
import css from './PlayerOverlayContents.module.less';
const SpottableBtn = Spottable("button");
const SpottableBtn = Spottable('button');
const Container = SpotlightContainerDecorator(
{ enterTo: "default-element" },
"div"
);
const Container = SpotlightContainerDecorator({ enterTo: 'default-element' }, 'div');
export default function PlayerOverlayContents({
type,
@@ -35,8 +32,11 @@ export default function PlayerOverlayContents({
videoVerticalVisible,
sideContentsVisible,
setSideContentsVisible,
belowContentsVisible,
handleIndicatorUpClick,
handleIndicatorDownClick,
tabContainerVersion,
tabIndexV2,
...rest
}) {
const cntry_cd = useSelector((state) => state.common.httpHeader?.cntry_cd);
@@ -49,7 +49,7 @@ export default function PlayerOverlayContents({
const backBtnRef = useRef(null);
useEffect(() => {
if (type === "MEDIA" && !panelInfo.modal && backBtnRef.current) {
if (type === 'MEDIA' && !panelInfo.modal && backBtnRef.current) {
Spotlight.focus(SpotlightIds.PLAYER_BACK_BUTTON);
}
}, [panelInfo?.shptmBanrTpNm, panelInfo.modal, backBtnRef.current]);
@@ -64,7 +64,7 @@ export default function PlayerOverlayContents({
const patncLogoPath = useMemo(() => {
let logo = playListInfo[selectedIndex]?.patncLogoPath;
if (type === "MEDIA") {
if (type === 'MEDIA') {
logo = panelInfo?.patncLogoPath;
}
@@ -73,7 +73,7 @@ export default function PlayerOverlayContents({
const partnerName = useMemo(() => {
let name = playListInfo[selectedIndex]?.patncNm;
if (type === "MEDIA") {
if (type === 'MEDIA') {
name = panelInfo?.patncNm;
}
@@ -82,11 +82,11 @@ export default function PlayerOverlayContents({
const showName = useMemo(() => {
let name = playListInfo[selectedIndex]?.showNm;
if (type === "MEDIA") {
if (type === 'MEDIA') {
name = panelInfo?.showNm;
}
return name ? name.replace(/<br\s*\/?>/gi, " ") : "";
return name ? name.replace(/<br\s*\/?>/gi, ' ') : '';
}, [playListInfo, selectedIndex, panelInfo]);
const onSpotlightMoveTabButton = (e) => {
@@ -97,15 +97,15 @@ export default function PlayerOverlayContents({
const onSpotlightMoveMediaButton = (e) => {
e.stopPropagation();
if (type === "LIVE") {
return Spotlight.focus("videoIndicator-down-button");
if (type === 'LIVE') {
return Spotlight.focus('videoIndicator-down-button');
}
Spotlight.focus("videoPlayer_mediaControls");
Spotlight.focus('videoPlayer_mediaControls');
};
const onSpotlightMoveSlider = useCallback(
(e) => {
if (type === "VOD") {
if (type === 'VOD') {
e.stopPropagation();
Spotlight.focus(SpotlightIds.PLAYER_SLIDER);
@@ -117,7 +117,24 @@ export default function PlayerOverlayContents({
const onSpotlightMoveSideTab = (e) => {
e.stopPropagation();
e.preventDefault();
Spotlight.focus("tab-0");
Spotlight.focus('tab-0');
};
const onSpotlightMoveBelowTab = (e) => {
e.stopPropagation();
e.preventDefault();
// tabIndexV2에 따라 다른 버튼으로 포커스 이동
if (tabIndexV2 === 0) {
// ShopNow 탭: Close 버튼으로
Spotlight.focus('below-tab-close-button');
} else if (tabIndexV2 === 1) {
// LIVE CHANNEL 탭: LIVE CHANNEL 버튼으로
Spotlight.focus('below-tab-live-channel-button');
} else if (tabIndexV2 === 2) {
// ShopNowButton: ShopNowButton으로
Spotlight.focus('below-tab-shop-now-button');
}
};
const onSpotlightMoveBackButton = () => {
@@ -125,11 +142,16 @@ export default function PlayerOverlayContents({
};
const currentSideButtonStatus = useMemo(() => {
if (type !== "MEDIA" && !panelInfo?.modal && !sideContentsVisible) {
if (
type !== 'MEDIA' &&
!panelInfo?.modal &&
!sideContentsVisible &&
tabContainerVersion === 1
) {
return true;
}
return false;
}, [panelInfo, sideContentsVisible]);
}, [panelInfo, sideContentsVisible, tabContainerVersion]);
const noLiveContentsVisible = useMemo(() => {
if (!Array.isArray(playListInfo) || playListInfo.length === 0) {
@@ -147,54 +169,63 @@ export default function PlayerOverlayContents({
return (
<>
<Container className={css.overlayContainer}>
{type !== "MEDIA" &&
playListInfo.length > 1 &&
noLiveContentsVisible && (
<>
<div className={css.indicatorUpButton}>
<SpottableBtn
onClick={handleIndicatorUpClick}
spotlightId="videoIndicator-up-button"
onSpotlightRight={
videoVerticalVisible
? onSpotlightMoveSideTab
: onSpotlightMoveTabButton
}
onSpotlightDown={onSpotlightMoveSlider}
aria-label="Previous channel"
/>
</div>
<div className={css.indicatorDownButton}>
<SpottableBtn
onClick={handleIndicatorDownClick}
spotlightId="videoIndicator-down-button"
onSpotlightLeft={onSpotlightMoveSlider}
onSpotlightUp={onSpotlightMoveSlider}
onSpotlightRight={
videoVerticalVisible
? onSpotlightMoveSideTab
: onSpotlightMoveSlider
}
aria-label="Next channel"
/>
</div>
</>
)}
{type !== 'MEDIA' && playListInfo.length > 1 && noLiveContentsVisible && (
<>
<div className={css.indicatorUpButton}>
<SpottableBtn
onClick={handleIndicatorUpClick}
spotlightId="videoIndicator-up-button"
onSpotlightRight={
videoVerticalVisible
? onSpotlightMoveSideTab
: tabContainerVersion === 1
? onSpotlightMoveTabButton
: undefined
}
onSpotlightDown={
tabContainerVersion === 2 && belowContentsVisible
? onSpotlightMoveBelowTab
: onSpotlightMoveSlider
}
aria-label="Previous channel"
/>
</div>
<div className={css.indicatorDownButton}>
<SpottableBtn
onClick={handleIndicatorDownClick}
spotlightId="videoIndicator-down-button"
onSpotlightLeft={onSpotlightMoveSlider}
onSpotlightUp={onSpotlightMoveSlider}
onSpotlightRight={
videoVerticalVisible
? onSpotlightMoveSideTab
: tabContainerVersion === 1
? onSpotlightMoveTabButton
: undefined
}
onSpotlightDown={
tabContainerVersion === 2 && belowContentsVisible
? onSpotlightMoveBelowTab
: undefined
}
aria-label="Next channel"
/>
</div>
</>
)}
{currentSideButtonStatus && !videoVerticalVisible && (
<PlayerTabButton
setSideContentsVisible={setSideContentsVisible}
sideContentsVisible={sideContentsVisible}
onSpotlightLeft={
type !== "MEDIA" &&
playListInfo.length < 2 &&
onSpotlightMoveBackButton
type !== 'MEDIA' && playListInfo.length < 2 && onSpotlightMoveBackButton
}
videoType={type}
/>
)}
{cntry_cd === "US" && (
{cntry_cd === 'US' && (
<div className={css.videoButtonContainer}>
<SpottableBtn
className={classNames(
@@ -214,13 +245,17 @@ export default function PlayerOverlayContents({
onClick={onClickBack}
className={css.backIcon}
spotlightId="player-back-button"
onSpotlightDown={onSpotlightMoveMediaButton}
onSpotlightDown={
tabContainerVersion === 2 && belowContentsVisible
? onSpotlightMoveBelowTab
: onSpotlightMoveMediaButton
}
aria-label="Video Player Close"
ref={backBtnRef}
/>
<div
className={classNames(type === "LIVE" && css.liveIcon)}
aria-label={type === "LIVE" && "Live Icon"}
className={classNames(type === 'LIVE' && css.liveIcon)}
aria-label={type === 'LIVE' && 'Live Icon'}
/>
{partnerName && (
@@ -235,17 +270,14 @@ export default function PlayerOverlayContents({
<h2 className={css.patnerName}>{partnerName}</h2>
<Marquee
className={classNames(
css.title,
videoVerticalVisible && css.videoVerticalMarquee
)}
className={classNames(css.title, videoVerticalVisible && css.videoVerticalMarquee)}
marqueeOn="render"
>
{showName}
</Marquee>
</div>
</Container>
{type === "VOD" && disclaimer && (
{type === 'VOD' && disclaimer && (
<div className={css.disclaimer}>
<span className={css.icon} />
<h3 aria-label={disclaimer}>{disclaimer}</h3>

View File

@@ -971,7 +971,11 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
}
if (!panelInfo.modal && !videoVerticalVisible && !hasProperSpot) {
Spotlight.focus(SpotlightIds.PLAYER_TAB_BUTTON);
if (tabContainerVersion === 1) {
Spotlight.focus(SpotlightIds.PLAYER_TAB_BUTTON);
} else if (tabContainerVersion === 2) {
Spotlight.focus('below-tab-live-channel-button');
}
return;
}
//비디오 진입시 포커스
@@ -986,8 +990,8 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
panelInfo.modal,
panelInfo.isUpdatedByClick,
panelInfo.isIndicatorByClick,
panelInfo.shptmBanrTpNm,
tabContainerVersion,
]);
// 최상단 패널 정보 (여러 useMemo에서 공통으로 사용)
@@ -1943,10 +1947,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
console.log('[PlayerPanel] isOnTop true - 오버레이 표시');
setSideContentsVisible(true);
setBelowContentsVisible(true);
if (videoPlayer.current?.showControls) {
videoPlayer.current.showControls();
}
// VideoPlayer가 belowContentsVisible prop을 감지해서 자동으로 controls 표시함
}
}, [isOnTop, panelInfo.modal, videoVerticalVisible]);
@@ -2165,12 +2166,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
noAutoPlay={cannotPlay}
autoCloseTimeout={3000}
onBackButton={onClickBack}
spotlightDisabled={
(!videoVerticalVisible &&
panelInfo?.shptmBanrTpNm !== 'MEDIA' &&
sideContentsVisible) ||
panelInfo.modal
}
spotlightDisabled={panelInfo.modal}
isYoutube={isYoutube}
src={currentPlayingUrl}
style={panelInfo.modal ? modalStyle : {}}
@@ -2211,6 +2207,8 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
setCurrentTime={setCurrentTime}
setIsVODPaused={setIsVODPaused}
broadcast={broadcast}
tabContainerVersion={tabContainerVersion}
tabIndexV2={tabIndexV2}
>
{typeof window === 'object' && window.PalmSystem && (
<source src={currentPlayingUrl} type={videoType} />

View File

@@ -119,6 +119,16 @@ export default function LiveChannelContents({
patnerName={patncNm}
onClick={handleItemClick}
onFocus={handleFocus()}
onSpotlightUp={
version === 2 && index === 0
? (e) => {
// v2에서 첫 번째 아이템일 때 위로 가면 LIVE CHANNEL 버튼으로
e.stopPropagation();
e.preventDefault();
Spotlight.focus('below-tab-live-channel-button');
}
: undefined
}
type={TYPES.liveHorizontal}
spotlightId={`tabChannel-video-${index}`}
liveInfo={liveInfos[index]}

View File

@@ -3,6 +3,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux';
import { Job } from '@enact/core/util';
import Spotlight from '@enact/spotlight';
import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator';
import { getContainerNode, setContainerLastFocusedElement } from '@enact/spotlight/src/container';
@@ -169,6 +170,17 @@ export default function ShopNowContents({
productId={prdtId}
onClick={handleItemClick}
onFocus={handleFocus()}
spotlightId={`shop-now-item-${index}`}
onSpotlightUp={
version === 2 && index === 0
? (e) => {
// v2에서 첫 번째 아이템일 때 위로 가면 Close 버튼으로
e.stopPropagation();
e.preventDefault();
Spotlight.focus('below-tab-close-button');
}
: undefined
}
type={TYPES.horizontal}
version={version}
/>

View File

@@ -1,15 +1,26 @@
import React from 'react';
import Spotlight from '@enact/spotlight';
import Spottable from '@enact/spotlight/Spottable';
import { SpotlightIds } from '../../../../utils/SpotlightIds';
import css from './ShopNowButton.module.less';
const SpottableDiv = Spottable("div");
const SpottableDiv = Spottable('div');
export default function ShopNowButton({ onClick }) {
return (
<div className={css.container} spotlightId="shop-now-button-container">
<SpottableDiv className={css.shopNowButton} onClick={onClick}>
<div className={css.container}>
<SpottableDiv
className={css.shopNowButton}
onClick={onClick}
spotlightId="below-tab-shop-now-button"
onSpotlightUp={(e) => {
e.stopPropagation();
e.preventDefault();
Spotlight.focus(SpotlightIds.PLAYER_BACK_BUTTON);
}}
>
<span className={css.buttonText}>SHOP NOW</span>
</SpottableDiv>
</div>

View File

@@ -1,33 +1,25 @@
import React, {
useCallback,
useEffect,
} from 'react';
import React, { useCallback, useEffect } from 'react';
import classNames from 'classnames';
import Spotlight from '@enact/spotlight';
import SpotlightContainerDecorator
from '@enact/spotlight/SpotlightContainerDecorator';
import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator';
import Spottable from '@enact/spotlight/Spottable';
import icon_arrow_dwon
from '../../../../../assets/images/player/icon_tabcontainer_arrow_down.png';
import icon_shop_now
from '../../../../../assets/images/player/icon_tabcontainer_shopnow.png';
import icon_arrow_dwon from '../../../../../assets/images/player/icon_tabcontainer_arrow_down.png';
import icon_shop_now from '../../../../../assets/images/player/icon_tabcontainer_shopnow.png';
import { LOG_MENU } from '../../../../utils/Config';
import { $L } from '../../../../utils/helperMethods';
import { SpotlightIds } from '../../../../utils/SpotlightIds';
import LiveChannelContents from '../TabContents/LiveChannelContents';
import ShopNowContents from '../TabContents/ShopNowContents';
import YouMayLikeContents from '../TabContents/YouMayLikeContents';
import ShopNowButton from './ShopNowButton';
import css from './TabContainer.v2.module.less';
const Container = SpotlightContainerDecorator(
{ enterTo: "last-focused" },
"div"
);
const Container = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div');
const SpottableDiv = Spottable("div");
const SpottableDiv = Spottable('div');
export default function TabContainerV2({
panelInfo,
@@ -48,10 +40,8 @@ export default function TabContainerV2({
tabVisible,
}) {
const tabList = [
$L("SHOP NOW"),
panelInfo?.shptmBanrTpNm === "LIVE"
? $L("LIVE CHANNEL")
: $L("FEATURED SHOWS"),
$L('SHOP NOW'),
panelInfo?.shptmBanrTpNm === 'LIVE' ? $L('LIVE CHANNEL') : $L('FEATURED SHOWS'),
];
useEffect(() => {
@@ -62,10 +52,8 @@ export default function TabContainerV2({
}
if (tabIndex === 1) {
const isLive = panelInfo?.shptmBanrTpNm === "LIVE";
nowMenu = isLive
? LOG_MENU.FULL_LIVE_CHANNELS
: LOG_MENU.FULL_FEATURED_SHOWS;
const isLive = panelInfo?.shptmBanrTpNm === 'LIVE';
nowMenu = isLive ? LOG_MENU.FULL_LIVE_CHANNELS : LOG_MENU.FULL_FEATURED_SHOWS;
}
if (nowMenu) {
@@ -87,7 +75,7 @@ export default function TabContainerV2({
if (videoVerticalVisible) {
e.stopPropagation();
e.preventDefault();
Spotlight.focus("spotlightId-video-contaienr");
Spotlight.focus('spotlightId-video-contaienr');
}
},
[videoVerticalVisible]
@@ -98,12 +86,22 @@ export default function TabContainerV2({
e.stopPropagation();
e.preventDefault();
if (onTabClose) {
onTabClose(1); // tabIndex를 -1로 설정
onTabClose(1); // tabIndex를 1로 설정
}
},
[onTabClose]
);
// 위 방향 포커스 이동 시 백 버튼으로 이동
const handleSpotlightUpToBackButton = useCallback((e) => {
e.stopPropagation();
e.preventDefault();
// VideoPlayer가 belowContentsVisible prop을 감지해서 이미 controls를 표시했으므로
// 바로 포커스 이동
Spotlight.focus(SpotlightIds.PLAYER_BACK_BUTTON);
}, []);
// useEffect(()=>{
// console.log('[tabIndex]',tabIndex)
// },[tabIndex])
@@ -122,17 +120,21 @@ export default function TabContainerV2({
<div className={css.shopNowHeader}>
<div className={css.shopNowHeaderLeft}>
<div className={css.shopNowIconWrapper}>
<img
src={icon_shop_now}
alt="shop now icon"
className={css.shopNowIcon}
/>
<img src={icon_shop_now} alt="shop now icon" className={css.shopNowIcon} />
</div>
<div className={css.shopNowHeaderText}>SHOP NOW</div>
</div>
<SpottableDiv
className={css.closeButton}
onClick={handleCloseButtonClick}
spotlightId="below-tab-close-button"
onSpotlightUp={handleSpotlightUpToBackButton}
onSpotlightDown={(e) => {
// 첫 번째 ShopNow 아이템으로 포커스 이동
e.stopPropagation();
e.preventDefault();
Spotlight.focus('shop-now-item-0');
}}
>
×
</SpottableDiv>
@@ -166,6 +168,11 @@ export default function TabContainerV2({
className={css.liveChannelButton}
onClick={onLiveChannelButtonClick}
spotlightId="below-tab-live-channel-button"
onSpotlightUp={handleSpotlightUpToBackButton}
onSpotlightDown={(e) => {
// 첫 번째 PlayerItem으로 포커스 이동
Spotlight.focus('tabChannel-video-0');
}}
>
<span className={css.buttonText}>LIVE CHANNEL</span>
<div className={css.arrowIcon}>
@@ -173,7 +180,7 @@ export default function TabContainerV2({
</div>
</SpottableDiv>
{panelInfo?.shptmBanrTpNm === "LIVE" && playListInfo && (
{panelInfo?.shptmBanrTpNm === 'LIVE' && playListInfo && (
<LiveChannelContents
tabTitle={tabList}
selectedIndex={selectedIndex}
@@ -192,9 +199,7 @@ export default function TabContainerV2({
</>
)}
{tabVisible && tabIndex === 2 && (
<ShopNowButton onClick={onShopNowButtonClick} />
)}
{tabVisible && tabIndex === 2 && <ShopNowButton onClick={onShopNowButtonClick} />}
</Container>
);
}