[TButtonTab] 공통 컴포넌트 - TButtonTab (탭바) 추가

This commit is contained in:
hyunwoo93.cha
2024-02-13 22:01:24 +09:00
parent af16d9789f
commit 113733c747
4 changed files with 227 additions and 0 deletions

View File

@@ -0,0 +1,66 @@
import React, { useCallback } from "react";
import classNames from "classnames";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import css from "./TButtonTab.module.less";
import TButtonTabItem from "./TButtonTabItem";
const Container = SpotlightContainerDecorator(
{ enterTo: "last-focused" },
"div"
);
export const LIST_TYPE = {
large: "large",
medium: "medium",
small: "small",
};
export const RIGHT_BUTTON_TYPE = {
sort: "sort",
};
export default function TButtonTab({
className,
selectedIndex,
onItemClick,
contents = [],
noMarquee = false,
listType = LIST_TYPE.medium,
spotlightId,
...rest
}) {
const onClick = useCallback(
(index) => (e) => {
if (onItemClick) {
onItemClick({ index, e });
}
},
[selectedIndex]
);
return (
<Container
className={classNames(css.tabs, css[listType], className)}
{...rest}
>
{contents.map((item, index) => {
return (
<TButtonTabItem
key={`buttonTabItem ${index}`}
selected={index === selectedIndex}
onClick={onClick(index)}
index={index}
selectedTabIndex={selectedIndex}
noMarquee={noMarquee}
listType={listType}
>
{item}
</TButtonTabItem>
);
})}
</Container>
);
}

View File

@@ -0,0 +1,17 @@
@import "../../style/CommonStyle.module.less";
@import "../../style/utils.module.less";
.tabs {
.size(@w: 1680px, @h: 67px);
display: flex;
position: relative;
&::after {
content: "";
position: absolute;
.size(@w: 100%, @h: 1px);
background-color: @COLOR_DARK_RED;
left: 0;
bottom: 0;
}
}

View File

@@ -0,0 +1,95 @@
import React, { useCallback, useRef, useState } from "react";
import classNames from "classnames";
import compose from "ramda/src/compose";
import { Job } from "@enact/core/util";
import Marquee, { MarqueeController } from "@enact/sandstone/Marquee";
import Spottable from "@enact/spotlight/Spottable";
import * as Config from "../../utils/Config";
import { convertNewlinesToBr } from "../../utils/helperMethods";
import css from "./TButtonTabItem.module.less";
const SpottableComponent = Spottable("div");
const ItemBase = ({
panelInfo,
selected,
onClick,
index,
selectedTabIndex,
spotlightDisabled = false,
noMarquee,
children,
listType,
...rest
}) => {
const [pressed, setPressed] = useState(false);
const [blur, setBlur] = useState(true);
const _onClick = useCallback(
(e) => {
if (onClick) {
onClick(e);
setPressed(true);
clearPressedJob.current.start();
}
},
[onClick]
);
const clearPressedJob = useRef(
new Job((func) => {
setPressed(false);
setTimeout(func, Config.TBUTTON_PRESS_DELAY);
}, Config.TBUTTON_PRESS_DELAY)
);
const _onBlur = useCallback(() => {
setPressed(false);
clearPressedJob.current.stop();
setBlur(true);
}, [pressed]);
const _onFocus = useCallback(() => {
setBlur(false);
}, [blur]);
return (
<SpottableComponent
{...rest}
className={classNames(
css.tItem,
selected && css.selected,
pressed && css.pressed,
css[listType]
)}
onClick={_onClick}
spotlightDisabled={spotlightDisabled}
spotlightId={`tab-${selectedTabIndex}`}
>
{noMarquee ? (
<div className={css.title}>{convertNewlinesToBr(children)}</div>
) : (
<Marquee
className={css.title}
alignment={"center"}
marqueeOn={!blur ? "focus" : undefined}
onFocus={_onFocus}
onBlur={_onBlur}
>
{children}
</Marquee>
)}
</SpottableComponent>
);
};
const ImageItemDecorator = compose(
MarqueeController({ mmarqueeOnFocus: true })
);
const TButtonTabItem = ImageItemDecorator(ItemBase);
export default TButtonTabItem;

View File

@@ -0,0 +1,49 @@
@import "../../style/CommonStyle.module.less";
@import "../../style/utils.module.less";
@BORDER_WIDTH: 1px;
.tItem {
min-width: 100px;
max-width: 500px;
height: calc(100% - @BORDER_WIDTH);
background-color: @COLOR_WHITE;
border-top-right-radius: 12px;
border-top-left-radius: 12px;
border: 1px solid @COLOR_GRAY02;
border-bottom: none;
box-sizing: border-box;
padding: 0 12px;
.title {
.font(@fontFamily: @baseFontBold, @fontSize: 24px);
color: @COLOR_GRAY03;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
&.selected {
background-color: @COLOR_DARK_RED;
border-color: @COLOR_DARK_RED;
.title {
color: @COLOR_WHITE;
}
}
&:focus-within {
background-color: @PRIMARY_COLOR_RED;
border-color: @PRIMARY_COLOR_RED;
.title {
color: @COLOR_WHITE;
}
}
&.medium {
min-width: 330px;
}
}