-
Notifications
You must be signed in to change notification settings - Fork 4
/
TabContainer.tsx
103 lines (89 loc) · 2.72 KB
/
TabContainer.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import * as React from "react";
import { Store } from "@reduxjs/toolkit";
import * as PropTypes from "prop-types";
import { Navigate, PathFor } from "../interfaces";
import { RootState } from "../store";
export interface TabContainerProps extends React.Props<TabContainerProps> {
store?: Store<RootState>;
csrfToken?: string;
tab: string;
class?: string;
}
export interface TabContainerContext {
pathFor: PathFor;
router: any;
}
/** Renders a list of navigation tabs and the content of the current tab.
Subclasses must define the tabs and the method to call when a new tab
is clicked. */
export abstract class TabContainer<
T extends TabContainerProps
> extends React.Component<T, any> {
context: TabContainerContext;
constructor(props) {
super(props);
this.handleSelect = this.handleSelect.bind(this);
this.currentTab = this.currentTab.bind(this);
this.defaultTab = this.defaultTab.bind(this);
this.tabs = this.tabs.bind(this);
this.tabClass = this.tabClass.bind(this);
this.tabDisplayName = this.tabDisplayName.bind(this);
this.renderTab = this.renderTab.bind(this);
}
static contextTypes: React.ValidationMap<TabContainerContext> = {
router: PropTypes.object.isRequired,
pathFor: PropTypes.func.isRequired,
};
render(): JSX.Element {
const className = this.props.class
? `tab-container ${this.props.class}`
: "tab-container";
return (
<div className={className}>
<ul className="nav nav-tabs">
{Object.keys(this.tabs()).map((name) => (
<li key={name} role="presentation" className={this.tabClass(name)}>
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
<a
href="javascript:void(0)"
onClick={this.handleSelect}
data-tabkey={name}
>
{this.tabDisplayName(name)}
</a>
</li>
))}
</ul>
<div className="tab-content">
{Object.keys(this.tabs()).map((name) =>
this.renderTab(name, this.tabs()[name])
)}
</div>
</div>
);
}
abstract handleSelect(event);
abstract tabs();
defaultTab() {
return Object.keys(this.tabs())[0];
}
currentTab() {
return this.props.tab || this.defaultTab();
}
tabClass(name) {
return this.currentTab() === name ? "active" : null;
}
tabDisplayName(name) {
const capitalized = name.charAt(0).toUpperCase() + name.slice(1);
return capitalized;
}
renderTab(name, children) {
const display = this.currentTab() === name ? "block" : "none";
return (
<div style={{ display }} key={name}>
{children}
</div>
);
}
}
export default TabContainer;