🔨 refactor: tabcommon -datnguyen

:%s
This commit is contained in:
unknown 2021-09-08 14:48:53 +07:00
parent e21fc5ee30
commit c4829f1d52
7 changed files with 172 additions and 95 deletions

View File

@ -1,8 +1,7 @@
import { useState } from 'react'
import {
ButtonCommon,
Layout, ModalInfo
} from 'src/components/common'
import { ButtonCommon, Layout, ModalInfo } from 'src/components/common'
import TabPane from 'src/components/common/TabCommon/components/TabPane/TabPane'
import TabCommon from 'src/components/common/TabCommon/TabCommon'
export default function Test() {
const [visible, setVisible] = useState(false)
const onClose = () => {
@ -13,10 +12,26 @@ export default function Test() {
}
return (
<>
<ButtonCommon onClick={onOpen}>open</ButtonCommon>
<ModalInfo visible={visible} onClose={onClose}>
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Nisi qui, esse eos nobis soluta suscipit aliquid nostrum corporis. Nihil eligendi similique recusandae minus mollitia aliquam, molestias fugit tenetur voluptatibus maiores et. Quaerat labore corporis inventore nostrum, amet autem exercitationem eligendi?
</ModalInfo>
<TabCommon center={true}>
<TabPane
active={true}
tabName={'dat datdat datdatdatdatdatdat'}
>
<div className="w-full">
datdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdatdat
</div>
</TabPane>
<TabPane active={true} tabName={'1234567890'}>
<div className="w-full">
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Suscipit harum sint maiores optio? Perspiciatis, necessitatibus pariatur, ut sed aperiam minus reiciendis alias deleniti eligendi obcaecati illum id maxime accusantium beatae.
</div>
</TabPane>
<TabPane active={true} tabName={'1'}>
<div className="w-full">
11111111111111111111111111111111111111111111111111111111111
</div>
</TabPane>
</TabCommon>
</>
)
}

View File

@ -1,21 +1,28 @@
@import '../../../styles/utilities';
.tabCommon {
@apply flex;
position: relative;
border-bottom: 2px solid #FBFBFB;
padding-top: 1.6rem;
padding-bottom: 1.6rem;
width: 100%;
.slider {
@apply inline-block;
height: .2rem;
border-radius: 3px;
background-color: var(--primary);
position: absolute;
z-index: 1200;
bottom: 0;
transition: all .4s linear;
.tabWapper{
@apply flex flex-col w-full;
.tabHeader{
@apply relative;
.tabList {
@apply flex;
position: relative;
border-bottom: 2px solid #FBFBFB;
padding: 0.8rem 0;
width: 100%;
&.center{
@apply justify-center;
}
}
.slider {
@apply inline-block;
height: .2rem;
border-radius: 3px;
background-color: var(--primary);
position: absolute;
z-index: 1200;
bottom: 0;
transition: all .25s linear;
}
}
}

View File

@ -1,36 +1,85 @@
import React, { RefObject, useEffect } from "react"
import React, {
Children,
PropsWithChildren,
ReactElement,
RefObject,
useEffect,
useRef,
useState,
cloneElement,
} from 'react'
import s from './TabCommon.module.scss'
import TabItem from './components/TabItem/TabItem'
import { TabPaneProps } from './components/TabPane/TabPane'
import classNames from 'classnames'
interface TabCommonProps {
tabs: {ref:RefObject<HTMLLIElement>, tabName: string, active: boolean, onClick: (tabIndex: number, tabPane?: string) => void}[];
defaultActiveTab: number;
sliderRef : RefObject<HTMLDivElement>;
slideToTab: (ref: any) => void;
defaultActiveTab?: number
children: React.ReactNode
center?:boolean
}
const TabCommon = ({ tabs, defaultActiveTab, sliderRef, slideToTab } : TabCommonProps) => {
const TabCommon = ({
defaultActiveTab = 0,
children,
center
}: TabCommonProps) => {
const [active, setActive] = useState(0)
const slider = useRef<HTMLDivElement>(null)
const headerRef = useRef<HTMLUListElement>(null)
useEffect(() => {
setActive(defaultActiveTab)
}, [])
useEffect(() => {
slideToTab(tabs[defaultActiveTab].ref);
}, [])
useEffect(() => {
slide(active)
}, [active])
return (
<ul className={s.tabCommon}>
{
tabs.map((tab) => {
return (
<li key={tab.tabName} ref={tab.ref}>
<TabItem onClick={tab.onClick} active={tab.active}>{tab.tabName}</TabItem>
</li>
)
})
}
<div ref={sliderRef} className={s.slider}></div>
function slide(index: number) {
const active = headerRef.current?.children
.item(index)
?.getBoundingClientRect()
const current = slider.current
if (current && active) {
let width = active.width - 24 <= 0 ? 24 : active.width - 24
let left = active.left
current.style.width = width.toString() + 'px'
current.style.left = left.toString() + 'px'
}
}
const onTabClick = (index: number) => {
setActive(index)
}
return (
<section className={s.tabWapper}>
<div className={s.tabHeader}>
<ul className={classNames(s.tabList,{[s.center]:center})} ref={headerRef}>
{Children.map(children, (tab, index) => {
let item = tab as ReactElement<PropsWithChildren<TabPaneProps>>
return (
<li key={item.props.tabName}>
<TabItem
active={active === index}
onClick={onTabClick}
tabIndex={index}
>
{item.props.tabName}
</TabItem>
</li>
)
})}
</ul>
)
<div ref={slider} className={s.slider}></div>
</div>
<div className={s.tabBody}>
{Children.map(children, (tab, index) => {
let item = tab as ReactElement<PropsWithChildren<TabPaneProps>>
return cloneElement(item, { active:index===active });
})
}</div>
</section>
)
}
export default TabCommon;
export default TabCommon

View File

@ -1,22 +1,14 @@
@import '../../../../styles/utilities';
@import '../../../../../styles/utilities';
.tabItem {
margin-right: 4.8rem;
padding-top: 1.6rem;
padding-bottom: 1.6rem;
margin-right:2.4rem;
padding: 0.8rem 0;
min-width: 2.4rem;
&:hover {
@apply cursor-pointer;
}
}
.tabItemActive {
@apply font-bold;
margin-right: 4.8rem;
padding-top: 1.6rem;
padding-bottom: 1.6rem;
&:hover {
@apply cursor-pointer;
&.tabItemActive {
@apply font-bold;
}
}

View File

@ -1,19 +1,32 @@
import React from "react"
import classNames from 'classnames'
import React, { RefObject, useRef } from 'react'
import s from './TabItem.module.scss'
interface TabItemProps {
active: boolean;
children: string;
onClick: (tabIndex: number, tabPane: string) => void;
active: boolean
children: string
onClick?: (tabIndex: number) => void
tabIndex: number
}
const TabItem = ({ active = false, children, onClick } : TabItemProps) => {
return (
<span onClick={onClick} className={active ? s.tabItemActive : s.tabItem} >
{children}
</span>
)
const TabItem = ({
active = false,
children,
onClick,
tabIndex,
}: TabItemProps) => {
const handleClick = () => {
onClick && onClick(tabIndex)
}
return (
<span
onClick={handleClick}
// className={active ? s.tabItemActive : s.tabItem}
className={classNames(s.tabItem, {[s.tabItemActive]:active})}
>
{children}
</span>
)
}
export default TabItem;
export default TabItem

View File

@ -1,20 +1,20 @@
@import '../../../../../../styles/utilities';
@import "../../../../../styles/utilities";
.tabPane {
@apply hidden;
animation-duration: 0.6s;
animation-name: appear;
@keyframes appear {
from {
margin-left: 100%;
width: 200%;
}
transition: all 0.6s;
// animation-duration: 0.6s;
// animation-name: appear;
// @keyframes appear {
// from {
// margin-left: 100%;
// width: 200%;
// }
to {
margin-left: 0%;
width: 100%;
}
}
// to {
// margin-left: 0%;
// width: 100%;
// }
// }
&.active {

View File

@ -2,15 +2,16 @@ import classNames from "classnames"
import React from "react"
import s from './TabPane.module.scss'
interface TabPaneProps {
active: string;
export interface TabPaneProps {
active: boolean;
children?: React.ReactNode;
tabName: string
}
const TabPane = ({ active="", children } : TabPaneProps) => {
const TabPane = ({ active, children } : TabPaneProps) => {
return (
<section className={classNames(s.tabPane, {
[s[active]] : active
[s.active] : active
})}>
{children}
</section>