Add tab components
This commit is contained in:
118
src/components/tab/TabGroup.tsx
Normal file
118
src/components/tab/TabGroup.tsx
Normal file
@@ -0,0 +1,118 @@
|
||||
import clsx from "clsx";
|
||||
import { HTMLProps, useState } from "react";
|
||||
|
||||
|
||||
export interface Tab {
|
||||
tabHeader: React.ReactNode;
|
||||
headerClasses?: string;
|
||||
tabContent: React.ReactNode;
|
||||
contentClasses?: string;
|
||||
active?: boolean;
|
||||
onTabClick?: () => void;
|
||||
}
|
||||
|
||||
export interface TabGroupProps extends HTMLProps<HTMLDivElement>{
|
||||
tabs: Tab[];
|
||||
}
|
||||
|
||||
|
||||
export default function TabGroup(props: TabGroupProps){
|
||||
const { tabs, className } = props;
|
||||
const [ activeTab, setActiveTab ] = useState<number>(tabs.map((tab, index) => tab.active ? index : undefined)[0] ?? 0);
|
||||
//TODO: Possible to maintain state of past tabs if we "cache" them in a useState<JSX.Element>() on their first render
|
||||
|
||||
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={clsx(
|
||||
className,
|
||||
"flex flex-col w-full"
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className="flex flex-row items-center justify-start"
|
||||
>
|
||||
{
|
||||
tabs.map((tab, index) => (
|
||||
<TabHeader
|
||||
key={index}
|
||||
tab={tab}
|
||||
active={activeTab === index}
|
||||
onClick={() => { setActiveTab(index); tab.onTabClick?.(); }}
|
||||
/>
|
||||
))
|
||||
}
|
||||
<div
|
||||
className="w-full h-full py-2 border-b border-(--text-color)"
|
||||
>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="flex flex-col items-center justify-center"
|
||||
>
|
||||
{
|
||||
tabs.map((tab, index) => (
|
||||
<TabContent
|
||||
key={index}
|
||||
tab={tab}
|
||||
active={activeTab === index}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function TabHeader({
|
||||
tab,
|
||||
onClick,
|
||||
active
|
||||
}:{
|
||||
tab: Tab;
|
||||
onClick: () => void;
|
||||
active: boolean;
|
||||
}){
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
tab.headerClasses,
|
||||
"px-4 py-2 rounded-t-lg cursor-pointer whitespace-nowrap",
|
||||
"border-x border-t border-(--text-color)",
|
||||
{
|
||||
"border-b border-(--text-color)": !active
|
||||
}
|
||||
)}
|
||||
onClick={onClick}
|
||||
>
|
||||
{tab.tabHeader}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function TabContent({
|
||||
tab,
|
||||
active
|
||||
}:{
|
||||
tab: Tab;
|
||||
active: boolean;
|
||||
}){
|
||||
if(!active){
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
tab.headerClasses,
|
||||
""
|
||||
)}
|
||||
>
|
||||
{tab.tabContent}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user