Skip to content

Commit 2c77eeb

Browse files
committed
fix: create our own Tabs component
1 parent d5c11bf commit 2c77eeb

File tree

4 files changed

+110
-20
lines changed

4 files changed

+110
-20
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626
},
2727
"dependencies": {
2828
"dayjs": "^1.11.13",
29-
"wired-elements": "^3.0.0-rc.6",
30-
"react-icons": "^4.8.0"
29+
"react-icons": "^4.8.0",
30+
"wired-elements": "^3.0.0-rc.6"
3131
},
3232
"devDependencies": {
3333
"@chromatic-com/storybook": "^1.8.0",

src/components/Item/Item.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ interface ItemProps {
77
children?: React.ReactNode;
88
selected?: boolean;
99
value?: string;
10+
onClick?: () => void;
11+
borderBottom?: string;
1012
}
1113

1214
const WiredItemComponent = createComponent({
@@ -15,8 +17,9 @@ const WiredItemComponent = createComponent({
1517
elementClass: _WiredItem
1618
});
1719

18-
const StyledItem = styled(WiredItemComponent)`
20+
const StyledItem = styled(WiredItemComponent)<{ borderBottom?: string }>`
1921
--wired-item-selected-color: #f90;
22+
border-bottom: ${({ borderBottom }) => borderBottom || 'none'};
2023
2124
opacity: 1;
2225
@@ -25,8 +28,8 @@ const StyledItem = styled(WiredItemComponent)`
2528
}
2629
`;
2730

28-
export const Item: React.FC<ItemProps> = ({ selected, children, value }) => (
29-
<StyledItem selected={selected} value={value}>
31+
export const Item: React.FC<ItemProps> = ({ selected, children, value, onClick, borderBottom }) => (
32+
<StyledItem selected={selected} value={value} onClick={onClick} borderBottom={borderBottom}>
3033
{children}
3134
</StyledItem>
3235
);

src/components/Tabs/Tabs.stories.tsx

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Meta, StoryObj } from '@storybook/react';
22
import { Tabs } from './Tabs';
3+
import { Card } from '../Card/Card';
34

45
const meta = {
56
title: 'Components/Tabs',
@@ -12,5 +13,45 @@ export default meta;
1213
type Story = StoryObj<typeof meta>;
1314

1415
export const Default: Story = {
15-
args: {}
16+
args: {
17+
selected: 'Tab 1',
18+
elevation: 1,
19+
width: '300px',
20+
tabs: [
21+
{
22+
title: 'Tab 1',
23+
content: (
24+
<div>
25+
<h3>Welcome to Tab 1</h3>
26+
<p>This is the content for the first tab. It can contain any React elements.</p>
27+
</div>
28+
),
29+
},
30+
{
31+
title: 'Tab 2',
32+
content: (
33+
<div>
34+
<h3>Tab 2 Content</h3>
35+
<Card elevation={2}>
36+
<p>You can even nest other wired components inside tabs!</p>
37+
</Card>
38+
</div>
39+
),
40+
},
41+
{
42+
title: 'Tab 3',
43+
content: (
44+
<div>
45+
<h3>Tab 3 Features</h3>
46+
<ul>
47+
<li>Fully customizable</li>
48+
<li>Maintains wired look</li>
49+
<li>Keyboard accessible</li>
50+
</ul>
51+
</div>
52+
),
53+
},
54+
],
55+
onChange: (selected) => console.log(`Selected tab: ${selected}`),
56+
},
1657
};

src/components/Tabs/Tabs.tsx

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,67 @@
11
import * as React from 'react';
2-
import { createComponent } from '@lit/react';
3-
import { WiredTabs as _WiredTabs } from 'wired-elements/lib/wired-tabs.js';
2+
import styled from 'styled-components';
3+
import { Item } from '../Item/Item';
4+
import { Card } from '../Card/Card';
5+
6+
interface Tab {
7+
title: string;
8+
content: React.ReactNode;
9+
}
410

511
interface TabsProps {
612
selected?: string;
713
onChange?: (selected: string) => void;
14+
tabs: Tab[];
15+
elevation?: number;
16+
width?: string;
817
}
918

10-
export const Tabs = ({ selected, onChange }: TabsProps) => (
11-
<TabsComponent
12-
selected={selected}
13-
onChange={(event) => onChange?.((event as unknown as CustomEvent).detail)}
14-
/>
15-
);
16-
17-
const TabsComponent = createComponent({
18-
react: React,
19-
tagName: 'wired-tabs',
20-
elementClass: _WiredTabs
21-
});
19+
const TabList = styled.div<{ width?: string }>`
20+
display: flex;
21+
gap: 8px;
22+
margin-bottom: 8px;
23+
width: ${({ width }) => width || '100%'};
24+
`;
25+
26+
const TabContent = styled(Card)`
27+
padding: 16px;
28+
min-height: 200px;
29+
`;
30+
31+
export const Tabs: React.FC<TabsProps> = ({ selected, onChange, tabs, elevation = 1, width }) => {
32+
const [activeTab, setActiveTab] = React.useState(selected || tabs[0]?.title);
33+
34+
React.useEffect(() => {
35+
if (selected) {
36+
setActiveTab(selected);
37+
}
38+
}, [selected]);
39+
40+
const handleTabClick = (title: string) => {
41+
setActiveTab(title);
42+
onChange?.(title);
43+
};
44+
45+
const activeContent = tabs.find(tab => tab.title === activeTab)?.content;
46+
47+
return (
48+
<div>
49+
<TabList width={width}>
50+
{tabs.map((tab) => (
51+
<Item
52+
key={tab.title}
53+
value={tab.title}
54+
selected={tab.title === activeTab}
55+
borderBottom={tab.title === activeTab ? '1px solid var(--wired-item-selected-color)' : 'none'}
56+
onClick={() => handleTabClick(tab.title)}
57+
>
58+
{tab.title}
59+
</Item>
60+
))}
61+
</TabList>
62+
<TabContent elevation={elevation === 0 ? undefined : elevation} width={width}>
63+
{activeContent}
64+
</TabContent>
65+
</div>
66+
);
67+
};

0 commit comments

Comments
 (0)