Add Tab component

This commit is contained in:
Chen Asraf
2018-01-27 16:13:40 +02:00
parent bd6594187f
commit f1bd857289
6 changed files with 175 additions and 5 deletions

View File

@@ -14,7 +14,8 @@ class {{Name}} extends React.Component<I.IProps, I.IState> {
return (
<div className={className}>
{{Name}} Component
<h3>{{Name}} Component</h3>
{this.props.children}
</div>
)
}

View File

@@ -3,6 +3,7 @@ import * as css from './Header.css'
import * as I from './Header.module'
import AddressBar from 'components/AddressBar/AddressBar'
import RequestPayload from 'components/RequestPayload/RequestPayload'
import { Tab, TabContainer } from 'components/Tabs/Tabs'
import SelectBox, { Option, styles as selectBoxStyle } from 'components/SelectBox/SelectBox'
import Button from 'components/Button/Button'
import axios, { AxiosResponse } from 'axios'
@@ -25,10 +26,12 @@ class Header extends React.Component<I.IProps, I.IState> {
<img src={logo} />
<NavBar store={this.props.store} />
</div>
<div className={css.requestDataContainer}>
<RequestPayload store={this.props.store} />
<RequestHeaders store={this.props.store} />
</div>
<TabContainer collapsible={true}>
<Tab label="Data" className={css.requestDataContainer}>
<RequestPayload store={this.props.store} />
<RequestHeaders store={this.props.store} />
</Tab>
</TabContainer>
</div>
)
}

View File

@@ -0,0 +1,36 @@
@import "../../_variables.css";
.TabsContainer {
/* */
}
.tab-strip {
border-bottom: 1px solid #ccc;
margin-top: -1px;
margin-bottom: 10px;
}
.tab-label {
padding: 7px 16px;
border-radius: 3px 3px 0 0;
border: 1px solid #ccc;
display: inline-block;
background: #f0f0f0;
text-align: center;
margin-bottom: -1px;
margin-right: 5px;
cursor: pointer;
&.active {
background: white;
border-bottom-color: transparent;
}
&:hover {
background: white;
}
}
.tab-content {
width: 100%;
}

6
src/components/Tabs/Tabs.css.d.ts vendored Normal file
View File

@@ -0,0 +1,6 @@
export const TabsContainer: string;
export const tabsContainer: string;
export const tabStrip: string;
export const tabLabel: string;
export const active: string;
export const tabContent: string;

22
src/components/Tabs/Tabs.module.d.ts vendored Normal file
View File

@@ -0,0 +1,22 @@
import * as React from 'react'
export interface ContainerProps {
className?: string
children: JSX.Element[] | JSX.Element
collapsible?: boolean
}
export interface ContainerState {
children: JSX.Element[]
activeIdx: number
collapsed: boolean
}
export interface TabProps {
className?: string
children: any | any[]
label: string
onClick?: (event: React.MouseEvent<HTMLDivElement>) => void
}
export type Tab = React.ComponentElement<TabProps, React.Component<TabProps>>

View File

@@ -0,0 +1,102 @@
import * as React from 'react'
import * as css from './Tabs.css'
import * as I from './Tabs.module'
import * as classNames from 'classnames'
export const Tab = (props: I.TabProps) => {
const children = (props.children.constructor === Array
? props.children : [props.children]) as I.Tab[]
const newProps = Object.assign({}, props)
delete newProps.children
return React.createElement('div', newProps, children)
}
export class TabContainer extends React.Component<I.ContainerProps, I.ContainerState> {
constructor(props: I.ContainerProps) {
const children = (props.children.constructor === Array
? props.children : [props.children]) as JSX.Element[]
super(props)
this.checkChildrenTypes(this.props.children, this.constructor.name)
this.state = {
children,
activeIdx: 0,
collapsed: false,
}
}
private checkChildrenTypes(children: React.ReactNode | JSX.Element[] | JSX.Element, componentName: string) {
let error: Error | null = null
React.Children.forEach(children, function (child: React.ReactElement<any>) {
if (child.type !== Tab) {
throw new Error('`' + componentName + '` children should be of type `Tab`.')
}
})
return true
}
private tabStrip() {
return this.state.children.map((child, idx) => {
const cls = classNames(css.tabLabel, {
[css.active]: idx === this.state.activeIdx
})
const { onClick }: I.TabProps = child.props
const onTabClick = this.onTabClick(idx, onClick)
return (
<div className={cls} key={`tab-${idx}`}
onClick={onTabClick}>
{child.props.label}
</div>
)
})
}
private tabContents() {
const Child = this.state.children[this.state.activeIdx]
const { children, className: tabClasses, ...rest }: I.TabProps = Child.props
const cls = classNames(tabClasses, css.tabContent)
return (
<Child.type className={cls}
{...rest}>
{children}
</Child.type>
)
}
private onTabClick(idx: number, callback?: (e: React.MouseEvent<HTMLDivElement>) => void) {
const commonClick = (e: React.MouseEvent<HTMLDivElement>) => {
this.setState({ activeIdx: idx })
}
if (callback) {
return (e: React.MouseEvent<HTMLDivElement>) => {
commonClick(e)
callback(e)
}
}
return (e: React.MouseEvent<HTMLDivElement>) => {
commonClick(e)
}
}
render() {
const className = classNames(css.TabsContainer, this.props.className)
return (
<div className={className}>
<div className={css.tabStrip}>
{this.tabStrip()}
</div>
{this.tabContents()}
</div>
)
}
}
export default TabContainer