[FeaturedBrandsPanel] section CATEGORY, scroll & focus 조정

Detail Notes :

1. 새로운 시나리오 가이드에 따른 DetailPanel 진입 이후 scroll & focus 조정
This commit is contained in:
younghoon100.park
2024-04-11 12:39:44 +09:00
parent ebe9338872
commit c2c145ae3f
9 changed files with 414 additions and 183 deletions

View File

@@ -10,7 +10,6 @@ import { useDispatch, useSelector } from "react-redux";
import { Job } from "@enact/core/util";
import Spotlight from "@enact/spotlight";
import { getContainerId } from "@enact/spotlight/src/container";
import {
getBrandBestSeller,
@@ -194,6 +193,8 @@ export default function FeaturedBrandsPanel() {
(state) => state.brand.brandShowroomData.status
);
const [firstFocusableTargetId, setFirstFocusableTargetId] = useState();
const [spotlightDisabled, setSpotlightDisabled] = useState(true);
const [selectedPatnrId, setSelectedPatnrId] = useState();
const [selectedBrandInfo, setSelectedBrandInfo] = useState();
const [selectedCatCd, setSelectedCatCd] = useState();
@@ -201,22 +202,10 @@ export default function FeaturedBrandsPanel() {
const [selectedSeriesId, setSelectedSeriesId] = useState();
const [selectedCatCdLv1, setSelectedCatCdLv1] = useState();
const [selectedCatCdLv2, setSelectedCatCdLv2] = useState();
const [targetId, setTargetId] = useState();
const [_, setForceUpdate] = useState({});
const [_, forceUpdate] = useState({});
const firstFocusableTargetId = useRef();
const getFirstFocusableTargetIdJob = useRef(
new Job(() => {
const target = document.querySelector(`[data-focusable-index="0"]`);
if (target) {
firstFocusableTargetId.current = getContainerId(target);
}
})
);
const focusJob = useRef(
new Job((targetId) => targetId && Spotlight.focus(targetId))
);
const forceUpdateJob = useRef(new Job(() => forceUpdate({}), 300));
const initialFocusTimeoutJob = useRef(new Job((func) => func(), 300));
const isLoading = useMemo(
() =>
@@ -246,6 +235,18 @@ export default function FeaturedBrandsPanel() {
]
);
const previousPanelIsDetail = Object.keys(panelInfo).length >= 4;
useEffect(() => {
if (panelInfo) {
console.log(
"%c pyh panelInfo",
"background:blue; color:white",
panelInfo
);
}
}, [panelInfo]);
useEffect(() => {
const showLoadingPanel = isLoading
? { show: true, type: "wait" }
@@ -255,73 +256,120 @@ export default function FeaturedBrandsPanel() {
}, [dispatch, isLoading]);
useEffect(() => {
if (panelInfo) {
console.log("pyh panelInfo", panelInfo);
console.log("pyh panelInfo.length", Object.keys(panelInfo).length);
// scrollTopBody({ animate: false });
if (!brandInfo) {
// console.log("%c 0 brandInfo effect", "background:blue; color:white");
dispatch(getBrandList());
}
}, [dispatch]);
useEffect(() => {
if (brandInfo && panelInfo) {
if (previousPanelIsDetail) {
// console.log(
// "%c pyh 1 initial Detail effect",
// "background:blue; color:white"
// );
if (Object.keys(panelInfo).length > 1) {
setSelectedBrandInfo(
findItemByValue(panelInfo?.brandInfo, panelInfo?.patnrId)
);
setTargetId(panelInfo?.targetId);
// pyh Todo, edit, scroll timing
setTimeout(() => scrollTopBody({ y: panelInfo.y, animate: false }));
setFirstFocusableTargetId(panelInfo?.firstFocusableTargetId);
return;
}
// console.log(
// "%c pyh 1 initial GNB or QuickMenu effect",
// "background:blue; color:white"
// );
scrollTopBody({ animate: false });
setSelectedPatnrId(panelInfo?.patnrId);
setTargetId("spotlightId-" + panelInfo?.patnrId);
setFirstFocusableTargetId("spotlightId-" + brandInfo[0]?.patnrId);
}
}, [panelInfo]);
}, [brandInfo, panelInfo]);
useEffect(() => {
if (!brandInfo) {
dispatch(getBrandList());
}
}, [brandInfo, dispatch]);
if (brandInfo && selectedPatnrId) {
// console.log(
// "%c pyh 2 selectedPatnrId effect",
// "background:blue; color:white"
// );
useEffect(() => {
if (brandInfo) {
getFirstFocusableTargetIdJob.current.start();
dispatch(getBrandLayoutInfo({ patnrId: selectedPatnrId }));
dispatch(getBrandLiveChannelInfo({ patnrId: selectedPatnrId }));
dispatch(getBrandTSVInfo({ patnrId: selectedPatnrId }));
dispatch(getBrandBestSeller({ patnrId: selectedPatnrId }));
dispatch(getBrandRecommendedShowInfo({ patnrId: selectedPatnrId }));
dispatch(getBrandCreatorsInfo({ patnrId: selectedPatnrId }));
dispatch(getBrandSeriesInfo({ patnrId: selectedPatnrId }));
dispatch(
getBrandCategoryInfo({
patnrId: selectedPatnrId,
})
);
dispatch(
getBrandShowroom({
patnrId: selectedPatnrId,
})
);
if (targetId) {
focusJob.current.start(targetId);
}
}
}, [brandInfo, targetId]);
useEffect(() => {
if (brandInfo) {
if (selectedPatnrId) {
setSelectedBrandInfo(findItemByValue(brandInfo, selectedPatnrId));
setSelectedCatCd();
setSelectedHstNm();
setSelectedSeriesId();
setSelectedCatCdLv1();
setSelectedCatCdLv2();
dispatch(getBrandLayoutInfo({ patnrId: selectedPatnrId }));
dispatch(getBrandLiveChannelInfo({ patnrId: selectedPatnrId }));
dispatch(getBrandTSVInfo({ patnrId: selectedPatnrId }));
dispatch(getBrandBestSeller({ patnrId: selectedPatnrId }));
dispatch(getBrandRecommendedShowInfo({ patnrId: selectedPatnrId }));
dispatch(getBrandCreatorsInfo({ patnrId: selectedPatnrId }));
dispatch(getBrandSeriesInfo({ patnrId: selectedPatnrId }));
dispatch(
getBrandCategoryInfo({
patnrId: selectedPatnrId,
})
);
dispatch(
getBrandShowroom({
patnrId: selectedPatnrId,
})
);
}
setSelectedBrandInfo(findItemByValue(brandInfo, selectedPatnrId));
setSelectedCatCd();
setSelectedHstNm();
setSelectedSeriesId();
setSelectedCatCdLv1();
setSelectedCatCdLv2();
}
}, [brandInfo, dispatch, selectedPatnrId]);
useEffect(() => {
if (selectedBrandInfo && firstFocusableTargetId) {
// console.log(
// "%c pyh *** focus effect ***",
// "background:blue; color:white"
// );
let targetId;
targetId = "spotlightId-" + panelInfo?.patnrId;
if (previousPanelIsDetail) {
// console.log(
// "%c pyh *** detail focus effect ***",
// "background:blue; color:white"
// );
if (panelInfo?.catCdLv1) {
setSelectedCatCdLv1(panelInfo?.catCdLv1);
}
if (panelInfo?.catCdLv2) {
setSelectedCatCdLv2(panelInfo?.catCdLv2);
}
if (panelInfo?.y) {
const { y } = panelInfo;
scrollTopBody({ y, animate: false });
}
targetId = panelInfo?.lastFocusedTargetId;
}
setSpotlightDisabled(false);
initialFocusTimeoutJob.current.start(() => {
const initialFocusTarget = document.querySelector(
`[data-spotlight-id="${targetId}"]`
);
// console.log("pyh initialFocusTarget?!?!\n\n", initialFocusTarget);
initialFocusTarget && Spotlight.focus(initialFocusTarget);
});
}
}, [selectedBrandInfo, firstFocusableTargetId]);
useEffect(() => {
if (selectedCatCd) {
dispatch(
@@ -356,47 +404,65 @@ export default function FeaturedBrandsPanel() {
}, [selectedSeriesId, dispatch]);
useEffect(() => {
setForceUpdate({});
if (selectedCatCdLv1 !== undefined || selectedCatCdLv2 !== undefined) {
forceUpdateJob.current.start();
}
return () => {
if (selectedCatCdLv1 !== undefined || selectedCatCdLv2 !== undefined) {
forceUpdateJob.current.stop();
}
};
}, [selectedCatCdLv1, selectedCatCdLv2]);
useEffect(() => {
return () => {
if (brandInfo) {
console.log("pyh -------------------- unmounted --------------------");
// console.log(
// "%c pyh ----------- unmounted -----------",
// "background:blue; color:white"
// );
const marker = document.querySelector(`[data-marker="scroll-marker"]`);
const firstFocusableTarget = document.querySelector(
`[data-focusable-index="0"]`
);
const lastFocusedTarget = Spotlight.getCurrent();
if (marker && lastFocusedTarget) {
const targetId = lastFocusedTarget.getAttribute("data-spotlight-id");
const markerRect = marker.getBoundingClientRect();
const lastFocusedTargetRect =
lastFocusedTarget.getBoundingClientRect();
const y = lastFocusedTargetRect.top - markerRect.top;
if (marker && lastFocusedTarget && firstFocusableTarget) {
const exprOrd = parseInt(
lastFocusedTarget.getAttribute("data-exposure-order")
);
const firstFocusableTargetId =
firstFocusableTarget.getAttribute("data-spotlight-id");
const lastFocusedTargetId =
lastFocusedTarget.getAttribute("data-spotlight-id");
dispatch(
updatePanel({
name: panel_names.FEATURED_BRANDS_PANEL,
panelInfo: { ...panelInfo, brandInfo, targetId, y },
panelInfo: {
brandInfo,
exprOrd,
firstFocusableTargetId,
lastFocusedTargetId,
},
})
);
}
getFirstFocusableTargetIdJob.current.stop();
focusJob.current.stop();
initialFocusTimeoutJob.current.stop();
}
};
}, [brandInfo]);
const handleTopButtonClick = useCallback(() => {
if (!firstFocusableTargetId.current) {
if (!firstFocusableTargetId) {
return scrollTopBody();
}
focusJob.current.start(firstFocusableTargetId.current);
Spotlight.focus(firstFocusableTargetId);
scrollTopBody();
}, []);
}, [firstFocusableTargetId]);
// pyh Todo, test, temporary func, edited later
const handlePopupClick = useCallback(() => {
@@ -415,15 +481,18 @@ export default function FeaturedBrandsPanel() {
return (
<TPanel className={css.tPanel}>
<TBody className={css.tBody} cbScrollTo={getScrollToBody}>
<TBody
className={css.tBody}
cbScrollTo={getScrollToBody}
spotlightDisabled={spotlightDisabled}
>
<div data-marker="scroll-marker" />
{shouldRenderComponent(brandInfo) && (
{shouldRenderComponent(brandInfo) && selectedBrandInfo && (
<QuickMenu
brandInfo={brandInfo}
scrollTopBody={scrollTopBody}
selectedPatnrId={selectedPatnrId}
setSelectedPatnrId={setSelectedPatnrId}
/>
)}

View File

@@ -105,6 +105,9 @@ export default memo(function FeaturedCategory({
isCarousel={array.length > 1}
key={"brand-category-product-info-" + index}
scrollTopBody={scrollTopBody}
selectedCatCdLv1={selectedCatCdLv1}
selectedCatCdLv2={selectedCatCdLv2}
selectedCategoryLv2Infos={selectedCategoryLv2Infos}
selectedPatnrId={selectedPatnrId}
/>
)

View File

@@ -16,9 +16,12 @@ export default function FeaturedCategoryContents({
index,
isCarousel,
scrollTopBody,
selectedCatCdLv1,
selectedCatCdLv2,
selectedCategoryLv2Infos,
selectedPatnrId,
}) {
const { brandCategoryProductDetailInfo, catNm, patnrId } =
const { brandCategoryProductDetailInfo, catCd, catNm, patnrId } =
brandCategoryProductDetailInfoItem;
return (
@@ -27,16 +30,26 @@ export default function FeaturedCategoryContents({
{isCarousel ? (
<FeaturedCategoryProductList
brandCategoryProductDetailInfo={brandCategoryProductDetailInfo}
catCd={catCd}
catNm={catNm}
index={index}
patnrId={patnrId}
scrollTopBody={scrollTopBody}
selectedCatCdLv1={selectedCatCdLv1}
selectedCatCdLv2={selectedCatCdLv2}
selectedCategoryLv2Infos={selectedCategoryLv2Infos}
selectedPatnrId={selectedPatnrId}
/>
) : (
<FeaturedCategoryProductGrid
brandCategoryProductDetailInfo={brandCategoryProductDetailInfo}
catCd={catCd}
index={index}
patnrId={patnrId}
scrollTopBody={scrollTopBody}
selectedCatCdLv1={selectedCatCdLv1}
selectedCatCdLv2={selectedCatCdLv2}
selectedCategoryLv2Infos={selectedCategoryLv2Infos}
/>
)}
</Container>

View File

@@ -1,20 +1,61 @@
import React, { useCallback } from "react";
import { useDispatch } from "react-redux";
import { useDispatch, useSelector } from "react-redux";
import { pushPanel } from "../../../../../actions/panelActions";
import TItemCard from "../../../../../components/TItemCard/TItemCard";
import { pushPanel, updatePanel } from "../../../../../actions/panelActions";
import TItemCard, {
removeDotAndColon,
} from "../../../../../components/TItemCard/TItemCard";
import useScrollTopByDistance from "../../../../../hooks/useScrollTopByDistance";
import { panel_names } from "../../../../../utils/Config";
import { SpotlightIds } from "../../../../../utils/SpotlightIds";
import css from "./FeaturedCategoryProductGrid.module.less";
export default function FeaturedCategoryProductGrid({
brandCategoryProductDetailInfo,
catCd,
index,
patnrId,
selectedCatCdLv1,
selectedCatCdLv2,
selectedCategoryLv2Infos,
scrollTopBody,
}) {
const { scrollTopByDistance } = useScrollTopByDistance();
const dispatch = useDispatch();
const panelInfo = useSelector((state) => state.panels.panels[0]?.panelInfo);
const { cursorVisible } = useSelector((state) => state.common.appStatus);
const handleClick = useCallback(
(prdtId) => {
const tBody = document.querySelector(
`[data-spotlight-id="${SpotlightIds.TBODY}"]`
);
const yContainer = tBody?.children[0]?.children[0]?.children[0];
if (yContainer) {
const catCdLv1 = selectedCategoryLv2Infos
? selectedCategoryLv2Infos.length > 0
? selectedCatCdLv1
: catCd
: "";
const catCdLv2 = selectedCatCdLv2 ?? "";
const section = "category";
const x = 0;
const y = yContainer.scrollTop;
dispatch(
updatePanel({
name: panel_names.FEATURED_BRANDS_PANEL,
panelInfo: { ...panelInfo, catCdLv1, catCdLv2, section, x, y },
})
);
}
dispatch(
pushPanel({
name: panel_names.DETAIL_PANEL,
@@ -22,23 +63,50 @@ export default function FeaturedCategoryProductGrid({
})
);
},
[patnrId]
[
catCd,
dispatch,
patnrId,
selectedCatCdLv1,
selectedCatCdLv2,
selectedCategoryLv2Infos,
]
);
const handleFocus = useCallback(
(itemIndex) => {
if (cursorVisible || itemIndex > 4) {
return;
}
scrollTopByDistance(
`[data-marker="scroll-marker"]`,
`[data-category-subtitle-index="${index}"]`,
scrollTopBody,
36
);
},
[cursorVisible]
);
return (
<div className={css.container}>
<ul>
{brandCategoryProductDetailInfo.map(
({ imgUrl, offerInfo, prdtId, prdtNm, priceInfo }, index) => (
<li key={"brandCategoryProductDetailInfo-" + index}>
({ imgUrl, offerInfo, prdtId, prdtNm, priceInfo }, itemIndex) => (
<li key={"brand-category-product-detail-info-" + itemIndex}>
<TItemCard
imageAlt={prdtNm}
imageSource={imgUrl}
onClick={() => handleClick(prdtId)}
onFocus={() => handleFocus(itemIndex)}
offerInfo={offerInfo}
priceInfo={priceInfo}
productId={prdtId}
productName={prdtNm}
spotlightId={
"category-grid-spotlightId-" + removeDotAndColon(prdtId)
}
/>
</li>
)

View File

@@ -7,8 +7,13 @@
flex-wrap: wrap;
padding: 22px 0 0 60px;
li {
margin: 0 18px 15px 0;
> li {
flex: none;
// tItemCard
> div {
margin: 0 18px 15px 0;
}
}
}
}

View File

@@ -2,33 +2,73 @@ import React, { memo, useCallback, useEffect, useRef } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Job } from "@enact/core/util";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import {
getContainerId,
setContainerLastFocusedElement,
} from "@enact/spotlight/src/container";
import { pushPanel } from "../../../../../actions/panelActions";
import TItemCard from "../../../../../components/TItemCard/TItemCard";
import { pushPanel, updatePanel } from "../../../../../actions/panelActions";
import TItemCard, {
removeDotAndColon,
} from "../../../../../components/TItemCard/TItemCard";
import TScroller from "../../../../../components/TScroller/TScroller";
import useScrollTo from "../../../../../hooks/useScrollTo";
import useScrollTopByDistance from "../../../../../hooks/useScrollTopByDistance";
import { panel_names } from "../../../../../utils/Config";
import { SpotlightIds } from "../../../../../utils/SpotlightIds";
import css from "./FeaturedCategoryProductList.module.less";
const Container = SpotlightContainerDecorator(
{ leaveFor: { right: "" }, enterTo: "last-focused" },
"div"
);
export default memo(function FeaturedCategoryProductList({
brandCategoryProductDetailInfo,
catCd,
catNm,
index,
patnrId,
scrollTopBody,
selectedCatCdLv1,
selectedCatCdLv2,
selectedCategoryLv2Infos,
selectedPatnrId,
}) {
const { getScrollTo, scrollLeft } = useScrollTo();
const { scrollTopByDistance } = useScrollTopByDistance();
const dispatch = useDispatch();
const panelInfo = useSelector((state) => state.panels.panels[0]?.panelInfo);
const { cursorVisible } = useSelector((state) => state.common.appStatus);
const timeoutRef = useRef();
const scrollLeftJob = useRef(new Job((func) => func(), 0));
useEffect(() => {
if (panelInfo?.section !== "category") {
return;
}
if (panelInfo?.exprOrd === index + 1) {
const { x } = panelInfo;
if (x === 0) {
return;
}
scrollLeftJob.current.start(() => scrollLeft({ x }));
}
return () => {
if (panelInfo?.exprOrd === index + 1) {
scrollLeftJob.current.stop();
}
};
}, []);
useEffect(() => {
const containerId = "featured-category-product-list-id-" + catNm;
@@ -36,39 +76,42 @@ export default memo(function FeaturedCategoryProductList({
if (container) {
const childrenId = getContainerId(container?.children[0].children[0]);
childrenId && setContainerLastFocusedElement(null, [childrenId]);
childrenId &&
setContainerLastFocusedElement(null, [containerId, childrenId]);
}
scrollLeft();
}, [selectedPatnrId]);
const setScrollTopBody = useCallback(() => {
const marker = document.querySelector(`[data-marker="scroll-marker"]`);
const subTitle = document.querySelector(
`[data-category-subtitle-index="${index}"]`
);
if (marker && subTitle) {
const markerRect = marker.getBoundingClientRect();
const subTitleRect = subTitle.getBoundingClientRect();
const subSectionGap = 36;
const y = subTitleRect.top - markerRect.top - subSectionGap;
timeoutRef.current = setTimeout(() => scrollTopBody({ y }));
} else {
console.error("subTitle not found");
}
}, []);
const handleBlur = useCallback(() => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
}, []);
}, [selectedCatCdLv1, selectedCatCdLv2, selectedPatnrId]);
const handleClick = useCallback(
(prdtId) => {
(e, prdtId) => {
const tItemCard = e.currentTarget;
const tBody = document.querySelector(
`[data-spotlight-id="${SpotlightIds.TBODY}"]`
);
const xContainer = tItemCard?.parentNode?.parentNode?.parentNode;
const yContainer = tBody?.children[0]?.children[0]?.children[0];
if (xContainer && yContainer) {
const catCdLv1 = selectedCategoryLv2Infos
? selectedCategoryLv2Infos.length > 0
? selectedCatCdLv1
: catCd
: "";
const catCdLv2 = selectedCatCdLv2;
const section = "category";
const x = xContainer.scrollLeft;
const y = yContainer.scrollTop;
dispatch(
updatePanel({
name: panel_names.FEATURED_BRANDS_PANEL,
panelInfo: { ...panelInfo, catCdLv1, catCdLv2, section, x, y },
})
);
}
dispatch(
pushPanel({
name: panel_names.DETAIL_PANEL,
@@ -76,7 +119,14 @@ export default memo(function FeaturedCategoryProductList({
})
);
},
[dispatch, patnrId]
[
catCd,
dispatch,
patnrId,
selectedCatCdLv1,
selectedCatCdLv2,
selectedCategoryLv2Infos,
]
);
const handleFocus = useCallback(() => {
@@ -84,13 +134,19 @@ export default memo(function FeaturedCategoryProductList({
return;
}
setScrollTopBody();
scrollTopByDistance(
`[data-marker="scroll-marker"]`,
`[data-category-subtitle-index="${index}"]`,
scrollTopBody,
36
);
}, [cursorVisible]);
return (
<div
<Container
className={css.container}
id={"featured-category-product-list-id-" + catNm}
spotlightId={"featured-category-product-list-id-" + catNm}
>
<TScroller
cbScrollTo={getScrollTo}
@@ -100,23 +156,26 @@ export default memo(function FeaturedCategoryProductList({
<ul>
{brandCategoryProductDetailInfo.map(
({ imgUrl, offerInfo, prdtId, prdtNm, priceInfo }, itemIndex) => (
<li key={"brand-category-product-detail-info-" + prdtId}>
<li key={"brand-category-product-detail-info-" + itemIndex}>
<TItemCard
data-exposure-order={index + 1}
imageAlt={prdtNm}
imageSource={imgUrl}
onBlur={handleBlur}
onClick={() => handleClick(prdtId)}
onClick={(e) => handleClick(e, prdtId)}
onFocus={handleFocus}
offerInfo={offerInfo}
priceInfo={priceInfo}
productId={prdtId}
productName={prdtNm}
spotlightId={
"category-list-spotlightId-" + removeDotAndColon(prdtId)
}
/>
</li>
)
)}
</ul>
</TScroller>
</div>
</Container>
);
});

View File

@@ -1,6 +1,6 @@
import React, { useCallback, useEffect, useRef } from "react";
import React, { useCallback, useEffect } from "react";
import { useSelector } from "react-redux";
import { useDispatch, useSelector } from "react-redux";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import {
@@ -8,10 +8,13 @@ import {
setContainerLastFocusedElement,
} from "@enact/spotlight/src/container";
import { updatePanel } from "../../../../actions/panelActions";
import TButton, { TYPES } from "../../../../components/TButton/TButton";
import TScroller from "../../../../components/TScroller/TScroller";
import useScrollReset from "../../../../hooks/useScrollReset";
import useScrollTo from "../../../../hooks/useScrollTo";
import useScrollTopByDistance from "../../../../hooks/useScrollTopByDistance";
import { panel_names } from "../../../../utils/Config";
import { $L } from "../../../../utils/helperMethods";
import css from "./FeaturedCategoryNav.module.less";
@@ -37,11 +40,14 @@ export default function FeaturedCategoryNav({
scrollLeft,
true
);
const { scrollTopByDistance } = useScrollTopByDistance();
const dispatch = useDispatch();
const panelInfo = useSelector((state) => state.panels.panels[0]?.panelInfo);
const { cursorVisible } = useSelector((state) => state.common.appStatus);
const timeoutRef = useRef();
useEffect(() => {
const containerId = "featured-category-nav-id";
const container = document.getElementById(containerId);
@@ -55,39 +61,32 @@ export default function FeaturedCategoryNav({
scrollLeft();
}, [selectedPatnrId]);
const setScrollTopBody = useCallback(() => {
const marker = document.querySelector(`[data-marker="scroll-marker"]`);
const sectionTitle = document.querySelector(`[data-title="category"]`);
if (marker && sectionTitle) {
const markerRect = marker.getBoundingClientRect();
const sectionTitleRect = sectionTitle.getBoundingClientRect();
const sectionGap = 58;
const y = sectionTitleRect.top - markerRect.top - sectionGap;
timeoutRef.current = setTimeout(() => scrollTopBody({ y }));
}
}, []);
const handleBlur = useCallback((index) => {
if (index === undefined) {
const handleBlur = useCallback((itemIndex) => {
if (itemIndex === undefined) {
handleStopScrolling();
}
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
}, []);
const handleClick = useCallback((catCdLv1) => {
setSelectedCatCdLv1(catCdLv1);
setSelectedCatCdLv2();
}, []);
const handleClick = useCallback(
(catCdLv1) => {
const x = 0;
dispatch(
updatePanel({
name: panel_names.FEATURED_BRANDS_PANEL,
panelInfo: { ...panelInfo, x },
})
);
setSelectedCatCdLv1(catCdLv1);
setSelectedCatCdLv2();
},
[dispatch]
);
const handleFocus = useCallback(
(index) => {
if (index === undefined) {
(itemIndex) => {
if (itemIndex === undefined) {
handleScrollReset();
}
@@ -95,7 +94,12 @@ export default function FeaturedCategoryNav({
return;
}
setScrollTopBody();
scrollTopByDistance(
`[data-marker="scroll-marker"]`,
`[data-title="category"]`,
scrollTopBody,
58
);
},
[cursorVisible]
);
@@ -125,7 +129,7 @@ export default function FeaturedCategoryNav({
</TButton>
</li>
{brandCategoryInfo &&
brandCategoryInfo.map(({ catCdLv1, catNmLv1 }, index) => (
brandCategoryInfo.map(({ catCdLv1, catNmLv1 }, itemIndex) => (
<li key={"brand-category-info-" + catCdLv1}>
<TButton
className={
@@ -133,9 +137,9 @@ export default function FeaturedCategoryNav({
selectedCatCdLv1 === catCdLv1 &&
css.selected
}
onBlur={() => handleBlur(index)}
onBlur={() => handleBlur(itemIndex)}
onClick={() => handleClick(catCdLv1)}
onFocus={() => handleFocus(index)}
onFocus={() => handleFocus(itemIndex)}
selected={selectedCatCdLv1 && selectedCatCdLv1 === catCdLv1}
type={TYPES.oneDepthCategory}
>

View File

@@ -1,10 +1,10 @@
import React, { useCallback } from "react";
import { useDispatch } from "react-redux";
import { useDispatch, useSelector } from "react-redux";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import { pushPanel } from "../../../../actions/panelActions";
import { pushPanel, updatePanel } from "../../../../actions/panelActions";
import TButton, { TYPES } from "../../../../components/TButton/TButton";
import TScroller from "../../../../components/TScroller/TScroller";
import useScrollReset from "../../../../hooks/useScrollReset";
@@ -38,13 +38,27 @@ export default function FeaturedSubCategoryNav({
const dispatch = useDispatch();
const panelInfo = useSelector((state) => state.panels.panels[0]?.panelInfo);
const handleBlur = useCallback(() => {
handleStopScrolling();
}, []);
const handleClick = useCallback((catCdLv2) => {
setSelectedCatCdLv2(catCdLv2);
}, []);
const handleClick = useCallback(
(catCdLv2) => {
const x = 0;
dispatch(
updatePanel({
name: panel_names.FEATURED_BRANDS_PANEL,
panelInfo: { ...panelInfo, x },
})
);
setSelectedCatCdLv2(catCdLv2);
},
[dispatch]
);
const handleFocus = useCallback(() => {
handleScrollReset();

View File

@@ -4,7 +4,7 @@ import { useDispatch } from "react-redux";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import { updatePanel } from "../../../actions/panelActions";
import { resetPanels, updatePanel } from "../../../actions/panelActions";
import TScroller from "../../../components/TScroller/TScroller";
import useScrollReset from "../../../hooks/useScrollReset";
import useScrollTo from "../../../hooks/useScrollTo";
@@ -21,7 +21,6 @@ export default memo(function QuickMenu({
brandInfo,
scrollTopBody,
selectedPatnrId,
setSelectedPatnrId,
}) {
const { getScrollTo, scrollLeft } = useScrollTo();
const { handleScrollReset, handleStopScrolling } = useScrollReset(
@@ -45,16 +44,13 @@ export default memo(function QuickMenu({
return;
}
dispatch(
updatePanel({
name: panel_names.FEATURED_BRANDS_PANEL,
panelInfo: { brandInfo, patnrId, y: 0 },
})
);
const name = panel_names.FEATURED_BRANDS_PANEL;
const panelInfo = { patnrId };
setSelectedPatnrId(patnrId);
dispatch(resetPanels([{ name }]));
dispatch(updatePanel({ name, panelInfo }));
},
[brandInfo, dispatch, selectedPatnrId]
[dispatch, selectedPatnrId]
);
const handleFocus = useCallback((index) => {