Skip to content

Commit 08a9630

Browse files
committed
feature: add tab components
1 parent 6a41df2 commit 08a9630

File tree

4 files changed

+259
-0
lines changed

4 files changed

+259
-0
lines changed

src/TabContainer.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import React from "react";
2+
import PropTypes from "prop-types";
3+
4+
const TabContainer = ({ children, color, controlled, ...rest }) => {
5+
const [newChildren, setNewChildren] = React.useState(() => {
6+
let newChildren = [];
7+
children.forEach((child, index) => {
8+
let grandChild = child.props.children;
9+
let targetTabContent = grandChild.props.target;
10+
let props = {
11+
...grandChild.props,
12+
color: color
13+
};
14+
if (!controlled) {
15+
props.onClick = () => toggleTabs(targetTabContent);
16+
}
17+
newChildren.push(
18+
React.cloneElement(child, {
19+
children: React.cloneElement(grandChild, props),
20+
key: index
21+
})
22+
);
23+
});
24+
return newChildren;
25+
});
26+
if (controlled) {
27+
return (
28+
<>
29+
<ul
30+
{...rest}
31+
className="flex mb-0 list-none flex-wrap pt-3 pb-4 flex-row"
32+
>
33+
{children}
34+
</ul>
35+
</>
36+
);
37+
}
38+
const toggleTabs = tabContentId => {
39+
let tabContent = document.querySelector(tabContentId);
40+
let newChildren = [];
41+
children.forEach((child, index) => {
42+
let grandChild = child.props.children;
43+
let targetTabContent = grandChild.props.target;
44+
document.querySelector(targetTabContent).classList.add("hidden");
45+
document.querySelector(targetTabContent).classList.remove("block");
46+
newChildren.push(
47+
React.cloneElement(child, {
48+
children: React.cloneElement(grandChild, {
49+
color: color,
50+
active: tabContentId === targetTabContent,
51+
onClick: () => toggleTabs(targetTabContent)
52+
}),
53+
key: index
54+
})
55+
);
56+
});
57+
setNewChildren(newChildren);
58+
tabContent.classList.add("block");
59+
tabContent.classList.remove("hidden");
60+
};
61+
return (
62+
<>
63+
<ul
64+
{...rest}
65+
className="flex mb-0 list-none flex-wrap pt-3 pb-4 flex-row"
66+
>
67+
{newChildren}
68+
</ul>
69+
</>
70+
);
71+
};
72+
73+
TabContainer.defaultProps = {
74+
color: "pink",
75+
controlled: false
76+
};
77+
78+
TabContainer.propTypes = {
79+
// if you want to controll the behavior yourself
80+
controlled: PropTypes.bool,
81+
// set the background, border and text color for the tab-link
82+
color: PropTypes.oneOf([
83+
"black",
84+
"white",
85+
"gray",
86+
"red",
87+
"orange",
88+
"yellow",
89+
"green",
90+
"teal",
91+
"blue",
92+
"indigo",
93+
"purple",
94+
"pink"
95+
]),
96+
children: PropTypes.node
97+
};
98+
99+
export default TabContainer;

src/TabContent.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React from "react";
2+
import PropTypes from "prop-types";
3+
import classnames from "classnames";
4+
5+
const TabContent = React.forwardRef(
6+
({ children, id, active, ...rest }, ref) => {
7+
return (
8+
<>
9+
<div
10+
{...rest}
11+
id={id}
12+
className={classnames({ hidden: !active }, { block: active })}
13+
>
14+
{children}
15+
</div>
16+
</>
17+
);
18+
}
19+
);
20+
21+
TabContent.defaultProps = {
22+
active: false
23+
};
24+
25+
TabContent.propTypes = {
26+
show: PropTypes.bool,
27+
id: PropTypes.string.isRequired,
28+
children: PropTypes.node
29+
};
30+
31+
export default TabContent;

src/TabItem.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import React from "react";
2+
import PropTypes from "prop-types";
3+
4+
const TabItem = React.forwardRef(({ children, ...rest }, ref) => {
5+
return (
6+
<>
7+
<li {...rest} className="-mb-px mr-2 last:mr-0 flex-auto text-center">
8+
{children}
9+
</li>
10+
</>
11+
);
12+
});
13+
14+
TabItem.defaultProps = {};
15+
16+
TabItem.propTypes = {
17+
children: PropTypes.node
18+
};
19+
20+
export default TabItem;

src/TabLink.js

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import React from "react";
2+
import PropTypes from "prop-types";
3+
import classnames from "classnames";
4+
5+
const colorSchemes = {
6+
default: {
7+
black: "bg-white text-black",
8+
white: "bg-black text-white",
9+
gray: "bg-white text-gray-600",
10+
red: "bg-white text-red-600",
11+
orange: "bg-white text-orange-600",
12+
yellow: "bg-white text-yellow-600",
13+
green: "bg-white text-green-600",
14+
teal: "bg-white text-teal-600",
15+
blue: "bg-white text-blue-600",
16+
indigo: "bg-white text-indigo-600",
17+
purple: "bg-white text-purple-600",
18+
pink: "bg-white text-pink-600"
19+
},
20+
active: {
21+
black: "bg-black text-white",
22+
white: "bg-white text-black",
23+
gray: "text-white bg-gray-600",
24+
red: "text-white bg-red-600",
25+
orange: "text-white bg-orange-600",
26+
yellow: "text-white bg-yellow-600",
27+
green: "text-white bg-green-600",
28+
teal: "text-white bg-teal-600",
29+
blue: "text-white bg-blue-600",
30+
indigo: "text-white bg-indigo-600",
31+
purple: "text-white bg-purple-600",
32+
pink: "text-white bg-pink-600"
33+
},
34+
disabled: {
35+
black: "bg-gray-700 text-gray-100",
36+
white: "bg-gray-200 text-gray-400",
37+
gray: "text-gray-100 bg-gray-400",
38+
red: "text-gray-100 bg-red-400",
39+
orange: "text-gray-100 bg-orange-400",
40+
yellow: "text-gray-100 bg-yellow-400",
41+
green: "text-gray-100 bg-green-400",
42+
teal: "text-gray-100 bg-teal-400",
43+
blue: "text-gray-100 bg-blue-400",
44+
indigo: "text-gray-100 bg-indigo-400",
45+
purple: "text-gray-100 bg-purple-400",
46+
pink: "text-gray-100 bg-pink-400"
47+
}
48+
};
49+
50+
class TabLink extends React.Component {
51+
componentDidMount() {
52+
const { target, active } = this.props;
53+
if (active) {
54+
let tabContent = document.querySelector(target);
55+
tabContent.classList.add("block");
56+
tabContent.classList.remove("hidden");
57+
}
58+
}
59+
render() {
60+
const { children, disabled, active, color, target, ...rest } = this.props;
61+
return (
62+
<>
63+
<a
64+
{...rest}
65+
className={classnames(
66+
{ [colorSchemes.default[color]]: !active && !disabled },
67+
{ [colorSchemes.active[color]]: active && !disabled },
68+
{ [colorSchemes.disabled[color]]: disabled },
69+
{ "pointer-events-none": disabled },
70+
"block py-2 px-4 no-underline rounded cursor-pointer shadow-lg"
71+
)}
72+
>
73+
{children}
74+
</a>
75+
</>
76+
);
77+
}
78+
}
79+
80+
TabLink.defaultProps = {
81+
disabled: false,
82+
active: false,
83+
color: "white"
84+
};
85+
86+
TabLink.propTypes = {
87+
disabled: PropTypes.bool,
88+
active: PropTypes.bool,
89+
// set the background, border and text color for the tab-link
90+
color: PropTypes.oneOf([
91+
"black",
92+
"white",
93+
"gray",
94+
"red",
95+
"orange",
96+
"yellow",
97+
"green",
98+
"teal",
99+
"blue",
100+
"indigo",
101+
"purple",
102+
"pink"
103+
]),
104+
// the tab-content that will be displayed by pressing this tab-link
105+
target: PropTypes.string.isRequired,
106+
children: PropTypes.node
107+
};
108+
109+
export default TabLink;

0 commit comments

Comments
 (0)