64 lines
1.8 KiB
TypeScript
64 lines
1.8 KiB
TypeScript
import React, { ReactNode } from 'react';
|
|
import classNames from 'classnames';
|
|
|
|
interface TabProps<T> {
|
|
label: string;
|
|
identifier: T;
|
|
icon?: ReactNode;
|
|
children: ReactNode;
|
|
}
|
|
|
|
export const Tab = <T,>({ children }: TabProps<T>) => {
|
|
// Wrapper component
|
|
return <>{children}</>;
|
|
};
|
|
|
|
interface TabViewProps<T> {
|
|
children: ReactNode;
|
|
selectedTab: T;
|
|
onTabChange: (tab: T) => void;
|
|
}
|
|
|
|
export const TabView = <T,>({ children, selectedTab, onTabChange }: TabViewProps<T>) => {
|
|
// Filter and validate children to only get Tab components
|
|
const tabs = React.Children.toArray(children).filter(
|
|
(child) => React.isValidElement(child) && child.type === Tab
|
|
) as React.ReactElement<TabProps<T>>[];
|
|
|
|
return (
|
|
<div className="flex flex-col flex-1 overflow-hidden">
|
|
<div className="flex flex-row h-11 border-b border-white/20">
|
|
{tabs.map((tab, index) => {
|
|
const isSelected = selectedTab === tab.props.identifier;
|
|
const rowClassName = classNames(
|
|
"flex flex-row items-center justify-center w-full gap-2 text-white",
|
|
{ "qc-highlighted": isSelected }
|
|
);
|
|
|
|
return (
|
|
<div
|
|
key={index}
|
|
className={rowClassName}
|
|
onClick={() => onTabChange(tab.props.identifier)}
|
|
>
|
|
{tab.props.icon}
|
|
<div className="text-sm font-bold">{tab.props.label}</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
<div className="flex-1 overflow-hidden">
|
|
{tabs.map((tab, index) => (
|
|
<div
|
|
key={index}
|
|
className={classNames("w-full h-full", {
|
|
hidden: selectedTab !== tab.props.identifier,
|
|
})}
|
|
>
|
|
{tab.props.children}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|