mirror of
https://github.com/DefectingCat/DefectingCat.github.io
synced 2025-07-16 01:01:38 +00:00
Add custom tab component
This commit is contained in:
73
components/RUA/tab/index.tsx
Normal file
73
components/RUA/tab/index.tsx
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import classNames from 'classnames';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
defaultValue: string | number;
|
||||||
|
children: React.ReactElement<ItemProps>[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const Tab = ({ defaultValue, children }: Props) => {
|
||||||
|
const [currentValue, setCurrentValue] = useState(defaultValue);
|
||||||
|
const handleSwitch = useCallback((value: ItemProps['value']) => {
|
||||||
|
setCurrentValue(value);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Pass current selected state to child
|
||||||
|
const childrenWithProps = React.Children.map(children, (child) => {
|
||||||
|
if (React.isValidElement(child)) {
|
||||||
|
return React.cloneElement(child, {
|
||||||
|
showContent: child.props.value === currentValue,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return child;
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<ul role="tablist" aria-orientation="horizontal" className="flex">
|
||||||
|
{children.map((child) => (
|
||||||
|
<li
|
||||||
|
role="tab"
|
||||||
|
aria-selected={currentValue === child.props.value}
|
||||||
|
key={child.props.label}
|
||||||
|
onClick={() => handleSwitch(child.props.value)}
|
||||||
|
className={classNames(
|
||||||
|
'px-4 py-4 rounded-t-lg',
|
||||||
|
child.props.value === currentValue &&
|
||||||
|
'text-teal-500 border-b-[3px] border-teal-500',
|
||||||
|
'select-none cursor-pointer',
|
||||||
|
'min-w-[76px] text-center',
|
||||||
|
'hover:bg-gray-200 dark:hover:bg-rua-gray-800'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{child.props.label}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div className="mt-4">{childrenWithProps}</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
type ItemProps = {
|
||||||
|
value: string | number;
|
||||||
|
label: string | number;
|
||||||
|
showContent?: boolean;
|
||||||
|
children?: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
Tab.Item = function TabItem({ showContent, children }: ItemProps) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={classNames('hidden', showContent && '!block')}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Tab;
|
@ -3,6 +3,9 @@ import { NextPageWithLayout } from 'types';
|
|||||||
import avatar from 'public/images/img/avatar.svg';
|
import avatar from 'public/images/img/avatar.svg';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import Tab from 'components/RUA/tab';
|
||||||
|
|
||||||
|
const TabItem = Tab.Item;
|
||||||
|
|
||||||
const MainLayout = dynamic(() => import('layouts/MainLayout'));
|
const MainLayout = dynamic(() => import('layouts/MainLayout'));
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user