mirror of
https://github.com/vercel/commerce.git
synced 2025-07-24 02:31:24 +00:00
🔨 refactor: tabcommon -datnguyen
:%s
This commit is contained in:
@@ -1,8 +1,7 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import {
|
import { ButtonCommon, Layout, ModalInfo } from 'src/components/common'
|
||||||
ButtonCommon,
|
import TabPane from 'src/components/common/TabCommon/components/TabPane/TabPane'
|
||||||
Layout, ModalInfo
|
import TabCommon from 'src/components/common/TabCommon/TabCommon'
|
||||||
} from 'src/components/common'
|
|
||||||
export default function Test() {
|
export default function Test() {
|
||||||
const [visible, setVisible] = useState(false)
|
const [visible, setVisible] = useState(false)
|
||||||
const onClose = () => {
|
const onClose = () => {
|
||||||
@@ -13,10 +12,26 @@ export default function Test() {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ButtonCommon onClick={onOpen}>open</ButtonCommon>
|
<TabCommon center={true}>
|
||||||
<ModalInfo visible={visible} onClose={onClose}>
|
<TabPane
|
||||||
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?
|
active={true}
|
||||||
</ModalInfo>
|
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>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -1,21 +1,28 @@
|
|||||||
@import '../../../styles/utilities';
|
@import '../../../styles/utilities';
|
||||||
|
.tabWapper{
|
||||||
.tabCommon {
|
@apply flex flex-col w-full;
|
||||||
@apply flex;
|
.tabHeader{
|
||||||
position: relative;
|
@apply relative;
|
||||||
border-bottom: 2px solid #FBFBFB;
|
.tabList {
|
||||||
padding-top: 1.6rem;
|
@apply flex;
|
||||||
padding-bottom: 1.6rem;
|
position: relative;
|
||||||
width: 100%;
|
border-bottom: 2px solid #FBFBFB;
|
||||||
|
padding: 0.8rem 0;
|
||||||
.slider {
|
width: 100%;
|
||||||
@apply inline-block;
|
&.center{
|
||||||
height: .2rem;
|
@apply justify-center;
|
||||||
border-radius: 3px;
|
}
|
||||||
background-color: var(--primary);
|
|
||||||
position: absolute;
|
}
|
||||||
z-index: 1200;
|
.slider {
|
||||||
bottom: 0;
|
@apply inline-block;
|
||||||
transition: all .4s linear;
|
height: .2rem;
|
||||||
|
border-radius: 3px;
|
||||||
|
background-color: var(--primary);
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1200;
|
||||||
|
bottom: 0;
|
||||||
|
transition: all .25s linear;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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 s from './TabCommon.module.scss'
|
||||||
|
|
||||||
import TabItem from './components/TabItem/TabItem'
|
import TabItem from './components/TabItem/TabItem'
|
||||||
|
import { TabPaneProps } from './components/TabPane/TabPane'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
interface TabCommonProps {
|
interface TabCommonProps {
|
||||||
tabs: {ref:RefObject<HTMLLIElement>, tabName: string, active: boolean, onClick: (tabIndex: number, tabPane?: string) => void}[];
|
defaultActiveTab?: number
|
||||||
defaultActiveTab: number;
|
children: React.ReactNode
|
||||||
sliderRef : RefObject<HTMLDivElement>;
|
center?:boolean
|
||||||
slideToTab: (ref: any) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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(() => {
|
useEffect(() => {
|
||||||
slideToTab(tabs[defaultActiveTab].ref);
|
slide(active)
|
||||||
}, [])
|
}, [active])
|
||||||
|
|
||||||
return (
|
function slide(index: number) {
|
||||||
<ul className={s.tabCommon}>
|
const active = headerRef.current?.children
|
||||||
{
|
.item(index)
|
||||||
tabs.map((tab) => {
|
?.getBoundingClientRect()
|
||||||
return (
|
const current = slider.current
|
||||||
<li key={tab.tabName} ref={tab.ref}>
|
if (current && active) {
|
||||||
<TabItem onClick={tab.onClick} active={tab.active}>{tab.tabName}</TabItem>
|
let width = active.width - 24 <= 0 ? 24 : active.width - 24
|
||||||
</li>
|
let left = active.left
|
||||||
)
|
current.style.width = width.toString() + 'px'
|
||||||
})
|
current.style.left = left.toString() + 'px'
|
||||||
}
|
}
|
||||||
|
}
|
||||||
<div ref={sliderRef} className={s.slider}></div>
|
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>
|
</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
|
||||||
|
@@ -1,22 +1,14 @@
|
|||||||
@import '../../../../styles/utilities';
|
@import '../../../../../styles/utilities';
|
||||||
|
|
||||||
.tabItem {
|
.tabItem {
|
||||||
margin-right: 4.8rem;
|
margin-right:2.4rem;
|
||||||
padding-top: 1.6rem;
|
padding: 0.8rem 0;
|
||||||
padding-bottom: 1.6rem;
|
min-width: 2.4rem;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
@apply cursor-pointer;
|
@apply cursor-pointer;
|
||||||
}
|
}
|
||||||
}
|
&.tabItemActive {
|
||||||
|
@apply font-bold;
|
||||||
.tabItemActive {
|
|
||||||
@apply font-bold;
|
|
||||||
margin-right: 4.8rem;
|
|
||||||
padding-top: 1.6rem;
|
|
||||||
padding-bottom: 1.6rem;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
@apply cursor-pointer;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,19 +1,32 @@
|
|||||||
import React from "react"
|
import classNames from 'classnames'
|
||||||
|
import React, { RefObject, useRef } from 'react'
|
||||||
import s from './TabItem.module.scss'
|
import s from './TabItem.module.scss'
|
||||||
|
|
||||||
interface TabItemProps {
|
interface TabItemProps {
|
||||||
active: boolean;
|
active: boolean
|
||||||
children: string;
|
children: string
|
||||||
onClick: (tabIndex: number, tabPane: string) => void;
|
onClick?: (tabIndex: number) => void
|
||||||
|
tabIndex: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const TabItem = ({ active = false, children, onClick } : TabItemProps) => {
|
const TabItem = ({
|
||||||
|
active = false,
|
||||||
return (
|
children,
|
||||||
<span onClick={onClick} className={active ? s.tabItemActive : s.tabItem} >
|
onClick,
|
||||||
{children}
|
tabIndex,
|
||||||
</span>
|
}: 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
|
||||||
|
@@ -1,20 +1,20 @@
|
|||||||
@import '../../../../../../styles/utilities';
|
@import "../../../../../styles/utilities";
|
||||||
|
|
||||||
.tabPane {
|
.tabPane {
|
||||||
@apply hidden;
|
@apply hidden;
|
||||||
animation-duration: 0.6s;
|
transition: all 0.6s;
|
||||||
animation-name: appear;
|
// animation-duration: 0.6s;
|
||||||
@keyframes appear {
|
// animation-name: appear;
|
||||||
from {
|
// @keyframes appear {
|
||||||
margin-left: 100%;
|
// from {
|
||||||
width: 200%;
|
// margin-left: 100%;
|
||||||
}
|
// width: 200%;
|
||||||
|
// }
|
||||||
|
|
||||||
to {
|
// to {
|
||||||
margin-left: 0%;
|
// margin-left: 0%;
|
||||||
width: 100%;
|
// width: 100%;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
|
@@ -2,15 +2,16 @@ import classNames from "classnames"
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import s from './TabPane.module.scss'
|
import s from './TabPane.module.scss'
|
||||||
|
|
||||||
interface TabPaneProps {
|
export interface TabPaneProps {
|
||||||
active: string;
|
active: boolean;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
tabName: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const TabPane = ({ active="", children } : TabPaneProps) => {
|
const TabPane = ({ active, children } : TabPaneProps) => {
|
||||||
return (
|
return (
|
||||||
<section className={classNames(s.tabPane, {
|
<section className={classNames(s.tabPane, {
|
||||||
[s[active]] : active
|
[s.active] : active
|
||||||
})}>
|
})}>
|
||||||
{children}
|
{children}
|
||||||
</section>
|
</section>
|
||||||
|
Reference in New Issue
Block a user