Skip to content

Commit

Permalink
feat(components): create TabContainer component
Browse files Browse the repository at this point in the history
  • Loading branch information
pedrorezende committed Oct 15, 2024
1 parent 38754bf commit f1f1017
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 0 deletions.
66 changes: 66 additions & 0 deletions packages/components/src/TabContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { ActionButton, ActionButtonProps } from "@namada/components";
import clsx from "clsx";
import { useState } from "react";
import { twMerge } from "tailwind-merge";

type TabContents = {
title: React.ReactNode;
children: React.ReactNode;
};

type TabContainerProps = {
id: string;
title: string;
tabs: TabContents[];
} & ActionButtonProps<"button">;

export const TabContainer = ({
id,
title,
tabs,
...buttonProps
}: TabContainerProps): JSX.Element => {
const [activeTabIndex, setActiveTabIndex] = useState(0);
return (
<div>
<div role="tablist" aria-label={title} className="flex">
{tabs.map((tab: TabContents, index: number) => (
<ActionButton
key={index}
id={`tab-${id}-${index}`}
role="tab"
aria-selected={activeTabIndex === index}
aria-controls={`tabpanel-${id}-${index}`}
tabIndex={activeTabIndex === index ? 0 : -1} // Only the active tab is focusable
onClick={() => setActiveTabIndex(index)}
size="md"
backgroundColor="rblack"
textHoverColor="white"
{...buttonProps}
className={twMerge(
clsx("text-white py-4", {
"opacity-50": activeTabIndex !== index,
}),
buttonProps.className
)}
>
{tab.title}
</ActionButton>
))}
</div>

{/* Tab Panel */}
{tabs.map((tab: TabContents, index: number) => (
<div
key={index}
id={`tabpanel-${id}-${index}`}
role="tabpanel"
aria-labelledby={`tab-${id}-${index}`}
hidden={activeTabIndex !== index}
>
{tab.children}
</div>
))}
</div>
);
};
1 change: 1 addition & 0 deletions packages/components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export * from "./StyledSelectBox";
export * from "./StyledTable";
export * from "./StyledTableHead";
export * from "./StyledTableRow";
export * from "./TabContainer";
export * from "./Text";
export * from "./TickedRadioList";
export * from "./ToggleButton";
Expand Down
63 changes: 63 additions & 0 deletions storybook/src/stories/TabContainer.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { TabContainer } from "@namada/components";
import { Meta, Story } from "@storybook/react";

export default {
title: "Components/TabContainer",
component: TabContainer,
} as Meta;

// Template for generating stories
const Template: Story = (args) => <TabContainer {...args} />;

// Default story with 3 tabs
export const Default = Template.bind({});
Default.args = {
tabs: [
{
title: "Tab 1",
children: <div>This is the content of Tab 1</div>,
},
{
title: "Tab 2",
children: <div>This is the content of Tab 2</div>,
},
{
title: "Tab 3",
children: <div>This is the content of Tab 3</div>,
},
],
};

// Story with different tab content
export const CustomTabs = Template.bind({});
CustomTabs.args = {
tabs: [
{
title: "Introduction",
children: <div>Welcome to the introduction content</div>,
},
{
title: "Overview",
children: <div>Here is an overview of the content</div>,
},
{
title: "Details",
children: <div>This is where the details are explained</div>,
},
],
};

// Story with only two tabs
export const TwoTabs = Template.bind({});
TwoTabs.args = {
tabs: [
{
title: "First Tab",
children: <div>Content for the first tab</div>,
},
{
title: "Second Tab",
children: <div>Content for the second tab</div>,
},
],
};

0 comments on commit f1f1017

Please sign in to comment.