TabLayout focus 수정(진행중)

This commit is contained in:
고동영
2024-02-02 17:09:32 +09:00
parent 0178f056f4
commit 75458ac163
7 changed files with 156 additions and 103 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -12,7 +12,6 @@ import compose from "ramda/src/compose";
import { Job } from "@enact/core/util"; import { Job } from "@enact/core/util";
import { Marquee, MarqueeController } from "@enact/sandstone/Marquee"; import { Marquee, MarqueeController } from "@enact/sandstone/Marquee";
import Spottable from "@enact/spotlight/Spottable"; import Spottable from "@enact/spotlight/Spottable";
import { getTargetByDirectionFromElement } from "@enact/spotlight/src/target";
import css from "./TabItem.module.less"; import css from "./TabItem.module.less";
@@ -24,23 +23,17 @@ const TabItemBase = ({
selected = false, selected = false,
index = 0, index = 0,
target, target,
panel,
deActivateTab, deActivateTab,
className,
onClick, onClick,
mainExpandend,
lgCatCd, lgCatCd,
isSubItem, isSubItem,
subTitle,
showSubTab = false,
onFocus, onFocus,
path, path,
isArrow = false,
...rest ...rest
}) => { }) => {
const [focused, setFocused] = useState(false); const [focused, setFocused] = useState(false);
// const [subFocused , setSubFocused] = useState(false)
const [pressed, setPressed] = useState(false); const [pressed, setPressed] = useState(false);
const [changeFocused, setChangeFocused] = useState(false);
const itemRef = useRef(); const itemRef = useRef();
const clearPressedJob = useRef( const clearPressedJob = useRef(
@@ -51,16 +44,11 @@ const TabItemBase = ({
const _onClick = useCallback( const _onClick = useCallback(
(ev) => { (ev) => {
setPressed(true); setPressed(true);
setChangeFocused(false);
clearPressedJob.current.start(() => { clearPressedJob.current.start(() => {
if (onClick) { if (onClick) {
onClick({ index, target }); onClick({ index, target });
} }
}); });
setPressed(true);
onClick({ index, target });
}, },
[target, index, onClick] [target, index, onClick]
); );
@@ -69,38 +57,56 @@ const TabItemBase = ({
const _onFocus = useCallback(() => { const _onFocus = useCallback(() => {
setFocused(true); setFocused(true);
if (onFocus) { if (onFocus) {
onFocus(index); onFocus(index);
} }
}, [index]); }, [index, isArrow]);
const _onBlur = useCallback(() => { const _onBlur = useCallback(() => {
setFocused(false); setFocused(false);
setPressed(false); setPressed(false);
setChangeFocused(true);
clearPressedJob.current.stop();
}, []); }, []);
const isDivider = useMemo(() => { const isDivider = useMemo(() => {
return !title; if (!title || !path) {
return false;
}
return true;
}, []); }, []);
const onKeyDown = useCallback( const onKeyDown = useCallback(
(event) => { (event) => {
if (event.key === "ArrowRight") { if (event.key === "ArrowRight") {
const next = getTargetByDirectionFromElement( _onClick();
"right",
itemRef.current.node
);
if (!next && deActivateTab) {
deActivateTab();
}
} }
}, },
[deActivateTab] [deActivateTab]
); );
const ImageComponent = useCallback(() => {
return (
<>
<span className={classNames(css.outline)} />
<img src={path} alt="" />
</>
);
}, [path]);
const TextComponent = useCallback(() => {
return (
<>
{expanded && (
<Marquee
marqueeOn={"focus"}
className={classNames(css.text, isSubItem && css.subItem)}
>
{title}
</Marquee>
)}
</>
);
}, [title]);
const renderIcon = useCallback(() => { const renderIcon = useCallback(() => {
if (icons) { if (icons) {
const Component = icons; const Component = icons;
@@ -120,7 +126,7 @@ const TabItemBase = ({
} else { } else {
return null; return null;
} }
}, [focused, expanded]); }, [focused, expanded, selected]);
delete rest.hasChildren; delete rest.hasChildren;
delete rest.getChildren; delete rest.getChildren;
@@ -129,30 +135,26 @@ const TabItemBase = ({
ref={itemRef} ref={itemRef}
className={classNames( className={classNames(
css.tabItem, css.tabItem,
focused && css.focused, !path && focused && css.focused,
!isSubItem && focused && isArrow && css.arrow,
path && css.path,
isSubItem && css.subDepth, isSubItem && css.subDepth,
pressed && css.arrow, !path && !isDivider && selected && css.selected,
!isDivider && selected && css.selected focused && path && css.ImgFocus,
selected && css.ImgSelect
)} )}
onKeyDown={onKeyDown} onKeyDown={onKeyDown}
onFocus={_onFocus} onFocus={_onFocus}
onBlur={_onBlur} onBlur={_onBlur}
onClick={_onClick} onClick={_onClick}
spotlightDisabled={isDivider}
> >
<div className={classNames(css.layout, focused && css.focused)}> <div className={css.layout}>
{icons && <div className={css.icon}>{renderIcon()}</div>} {icons && <div className={css.icon}>{renderIcon()}</div>}
<div className={classNames(isSubItem && css.subWrap)}> <div className={classNames(isSubItem && css.subWrap)}>
<span className={classNames(css[`category-icon-${lgCatCd}`])} /> <span className={css[`category-icon-${lgCatCd}`]} />
{expanded && ( {path ? <ImageComponent /> : <TextComponent />}
<Marquee
marqueeOn={"focus"}
className={classNames(css.text, isSubItem && css.subItem)}
>
{path ? <img src={path} alt="" /> : title}
</Marquee>
)}
</div> </div>
</div> </div>
</SpottableComponent> </SpottableComponent>

View File

@@ -3,16 +3,25 @@
@ICON_SIZE: 48px; @ICON_SIZE: 48px;
.spottable-next-left {
display:none;
}
.tabItem{ .tabItem{
font-size: 36px; font-size: 36px;
display: flex; display: flex;
color: #606060; color: #606060;
align-items: center; align-items: center;
height: 84px; height: 84px;
position: relative;
padding-left: 42px; padding-left: 42px;
padding-right: 24px; padding-right: 24px;
// .spottable-next-left {
// background-color: red;
// }
&.focused { &.focused {
color: #eee; color: #eee;
background: linear-gradient(to right, #cb1253, #e15ba1); background: linear-gradient(to right, #cb1253, #e15ba1);
@@ -21,11 +30,6 @@
z-index: 1; z-index: 1;
margin-left: 30px; margin-left: 30px;
position:relative; position:relative;
> div{
margin-left:-30px;
}
}
&.arrow { &.arrow {
&::after { &::after {
@@ -34,10 +38,14 @@
.position(@position: absolute, @top: 24px, @right: 18px); .position(@position: absolute, @top: 24px, @right: 18px);
background-image: url('../../../assets/icons/ic-lnb-right-arrow.png'); background-image: url('../../../assets/icons/ic-lnb-right-arrow.png');
background-size: 36px 36px; background-size: 36px 36px;
} }
> div{
margin-left:-30px;
}
} }
}
&.selected { &.selected {
color: #eee; color: #eee;
} }
@@ -45,18 +53,57 @@
&.subDepth{ &.subDepth{
width: 386px; width: 386px;
height: 78px; height: 78px;
margin-left: 0; padding-left: 42px;
&.focused { &.focused {
background: rgba(255, 255, 255, .1); background: rgba(255, 255, 255, .1);
border-radius: 0px; border-radius: 0px;
border-right: 6px solid #c70850; border-right: 6px solid #c70850;
margin-left: 0px;
> div { > div {
padding-left: 30px; padding-left: 30px;
}
}
&.path {
padding-left: 0px;
margin-bottom: 70px;
}
.outline {
.position(@position: absolute, @top: 0, @right: auto, @bottom: auto, @left: 0);
.size(@w: 138px, @h:138px);
background-position: center;
background-size: cover;
}
}}} img {
.size(@w: 120px, @h: 120px);
}
&.ImgFocus {
.outline {
border-radius: 60px;
z-index: 99;
// box-shadow: -3px 0px 30px 0 #c70850;
// border: solid 1px #dadada;
background-image: url("../../../assets/icons/ic-tab-partners-focus@3x.png");
}
img {
.size(@w: 138px, @h: 138px);
}
}
&.ImgSelect {
img {
.size(@w: 138px, @h: 138px);
}
.outline {
background-image: url("../../../assets/icons/ic-tab-partners-lnb-selected@3x.png");
}
}
}
.icon { .icon {
position: relative; position: relative;
@@ -77,30 +124,28 @@
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
} }
} }
.text { .text {
line-height: 1.2; line-height: 1.2;
padding-left: 11px; padding-left: 11px;
.font(@fontFamily:@baseFontBold, @fontSize:36px); .font(@fontFamily:@baseFontBold, @fontSize:36px);
&.subItem { &.subItem {
.font (@fontFamily:@baseFontBold, @fontSize:30px); .font (@fontFamily:@baseFontBold, @fontSize:30px);
width: 245px; width: 245px;
}
}
.layout {
display: flex;
} }
.marqueeWrap {
width: 100%;
}
} }
.subWrap{ .subWrap{
.flex(); .flex();
span { span {
.size(@w: 40px, @h:40px); .size(@w: 40px, @h:40px);
background-size: cover; background-size: cover;
@@ -169,22 +214,7 @@
background-image: url("../../../assets/icons/ic-category-clearance-nor.png"); background-image: url("../../../assets/icons/ic-category-clearance-nor.png");
} }
} }
}
.layout {
display: flex;
&.focused, &.selected {
// margin-left: -30px;
}
} }
.marqueeWrap {
width: 100%;
}
}

View File

@@ -34,8 +34,6 @@ import TrendingNowIcon from "./iconComponents/TrendingNowIcon";
import TabItem from "./TabItem"; import TabItem from "./TabItem";
import css from "./TabLayout.module.less"; import css from "./TabLayout.module.less";
//이미지
const Container = SpotlightContainerDecorator( const Container = SpotlightContainerDecorator(
{ enterTo: "default-element" }, { enterTo: "default-element" },
"div" "div"
@@ -179,7 +177,9 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
case "Featured Brands": case "Featured Brands":
result = data?.shortFeaturedBrands.map((item) => ({ result = data?.shortFeaturedBrands.map((item) => ({
Id: item.patnrId,
path: item.patncLogoPath, path: item.patncLogoPath,
target: [{ name: panel_names.FEATURED_BRANDS_PANEL }],
})); }));
break; break;
case "My Page": case "My Page":
@@ -225,6 +225,7 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
id: subItem.id, id: subItem.id,
title: subItem.title, title: subItem.title,
path: subItem.path, path: subItem.path,
target: subItem.target,
})); }));
} }
} }
@@ -272,7 +273,8 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
const children = parent.childNodes; const children = parent.childNodes;
const index = Array.prototype.indexOf.call(children, event.target); const index = Array.prototype.indexOf.call(children, event.target);
setMainExpanded(true); setMainExpanded(true);
setMainSelectedIndex(index); setMainSelectedIndex(index - 1);
setSecondDepthReduce(false);
} else { } else {
if (!panelSwitching.current) { if (!panelSwitching.current) {
setMainExpanded(true); setMainExpanded(true);
@@ -288,7 +290,7 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
} }
case EXTRA_AREA: { case EXTRA_AREA: {
if (cursorVisible) { if (cursorVisible) {
deActivateTabJob.start(deActivateTab); // deActivateTabJob.start(deActivateTab);
return; return;
} }
} }
@@ -299,7 +301,7 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
return prev; return prev;
}); });
}, },
[cursorVisible, deActivateTab, focused] [cursorVisible, deActivateTab]
); );
const onTabBlur = useCallback( const onTabBlur = useCallback(
@@ -307,7 +309,7 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
switch (type) { switch (type) {
case ACTIVATED_MAIN: { case ACTIVATED_MAIN: {
if (!cursorVisible) { if (!cursorVisible) {
setMainExpanded(false); // setMainExpanded(false);
} }
break; break;
@@ -333,8 +335,12 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
[cursorVisible] [cursorVisible]
); );
const onFocus = () => { const onFocus = (index) => {
setFocused(true); setFocused(true);
setMainSelectedIndex(index);
if (showSubTab) {
setSecondDepthReduce((prev) => !prev);
}
}; };
const onBlur = () => { const onBlur = () => {
@@ -343,7 +349,6 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
const handleNavigation = useCallback( const handleNavigation = useCallback(
({ index, target }) => { ({ index, target }) => {
setMainSelectedIndex(index);
if (target) { if (target) {
dispatch(resetPanels(target)); dispatch(resetPanels(target));
deActivateTab(); deActivateTab();
@@ -359,6 +364,7 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
const onClickSubItem = useCallback( const onClickSubItem = useCallback(
({ index, target }) => { ({ index, target }) => {
if (target) { if (target) {
dispatch(resetPanels(target));
deActivateTab(); deActivateTab();
panelSwitching.current = true; panelSwitching.current = true;
panelSwitchingJob.start(panelSwitching); panelSwitchingJob.start(panelSwitching);
@@ -418,19 +424,17 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
} }
}, [tabActivated, showTab]); }, [tabActivated, showTab]);
useEffect(() => {}, []);
useEffect(() => { useEffect(() => {
setSecondDepthReduce(false); setSecondDepthReduce(false);
if (showSubTab) { if (showSubTab) {
tabs[mainSelectedIndex]?.children.map((item) => { tabs[mainSelectedIndex]?.children.map((item) => {
if (item.path) { if (item.path) {
console.log("#item.path", item.path);
setSecondDepthReduce(true); setSecondDepthReduce(true);
} }
}); });
} }
}, [showSubTab, mainSelectedIndex, secondDepthReduce]); }, [secondDepthReduce, showSubTab, focused]);
if (!showTab) { if (!showTab) {
return null; return null;
} }
@@ -485,6 +489,7 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
key={"tabitemExpanded" + index} key={"tabitemExpanded" + index}
onClick={handleNavigation} onClick={handleNavigation}
deActivateTab={deActivateTab} deActivateTab={deActivateTab}
isArrow={showSubTab}
icons={item.icons} icons={item.icons}
expanded={mainExpanded} expanded={mainExpanded}
selected={ selected={
@@ -505,7 +510,7 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
className={classNames( className={classNames(
css.tabWrap, css.tabWrap,
css.secondDepthLayout, css.secondDepthLayout,
// secondDepthReduce && css. secondDepthReduce && css.secondDepthReduce,
!showSubTab && css.hide !showSubTab && css.hide
)} )}
onFocus={onTabHasFocus(ACTIVATED_SUB)} onFocus={onTabHasFocus(ACTIVATED_SUB)}
@@ -517,16 +522,23 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
tabs[mainSelectedIndex]?.children.map((item, index) => { tabs[mainSelectedIndex]?.children.map((item, index) => {
return ( return (
<TabItem <TabItem
{...item}
key={"tabitemSubmenu" + index} key={"tabitemSubmenu" + index}
onClick={onClickSubItem} onClick={onClickSubItem}
expanded={true} expanded={true}
index={index} index={index}
isSubItem={true} isSubItem={true}
showSubTab={showSubTab}
deActivateTab={deActivateTab} deActivateTab={deActivateTab}
title={item.title} title={item.title}
lgCatCd={item.id} lgCatCd={item.id}
path={item.path} path={item.path}
isArrow={showSubTab}
// selected={
// (panels.length === 0 && index === 0) ||
// (Array.isArray(item.target) &&
// item.target[0]?.name &&
// panels[0]?.name === item.target[0]?.name)
// }
/> />
); );
})} })}

View File

@@ -8,7 +8,6 @@
left: 0; left: 0;
top: 0; top: 0;
display: flex; display: flex;
// display: none;
&.hide { &.hide {
width: auto; width: auto;
@@ -40,7 +39,7 @@
justify-content: center; justify-content: center;
z-index: 1; z-index: 1;
flex-grow: 0; flex-grow: 0;
transition: width 0.5s ease; // transition: width 0.5s ease;
> img { > img {
width: 54px; width: 54px;
@@ -66,6 +65,16 @@
padding-top: 71px; padding-top: 71px;
z-index: 0; z-index: 0;
justify-content: flex-start; justify-content: flex-start;
&.secondDepthReduce {
width: 216px;
// transition: width 0.5s ease;
// > div {
// margin-bottom: 90px;
// }
}
} }
&.extraArea { &.extraArea {
flex-grow: 1; flex-grow: 1;