/* * Copyright (c) 2018-present, Revolut LTD. * * This source code is licensed under the Apache 2.0 license found in the * LICENSE file in the root directory of this source tree. */ import * as React from 'react' import makeControllable from 'make-controllable' import { TabsWrap, Pointer, TabItem, HiddenValue } from './styles' export type RenderItemDefaultProps = { item?: { id?: string title?: string titleFunc?: (...args: any[]) => any disabled?: boolean } state?: object handleChange?: (...args: any[]) => any index?: number valueIndex?: number } const renderItemDefault: React.SFC = ({ item = {}, state, handleChange, index, valueIndex, }) => { const content = item.titleFunc ? item.titleFunc(item, state) : item.title return ( handleChange(item.id)} >
{content}
{content}
) } const renderListDefault = ({ list = [], renderItem, state, ...restProps }) => { const valueIndex = list.findIndex(item => item.id === state.value) return list.map((item, index) => renderItem({ ...restProps, item, state, index, valueIndex, }), ) } const filterDisabled = (list = []) => list.filter(item => !item.disabled) export type TabsProps = { items?: { id?: string title?: string titleFunc?: (...args: any[]) => any disabled?: boolean }[] value?: string renderItem?: (...args: any[]) => any renderList?: (...args: any[]) => any onChange?: (...args: any[]) => any pointerPosition?: 'top' | 'bottom' showPointer?: boolean } type TabsState = { pointer: { left: string; width: string } value: any } export class Tabs extends React.Component { static defaultProps = { renderItem: renderItemDefault, renderList: renderListDefault, items: [], pointerPosition: 'bottom', showPointer: true, } state = { pointer: { left: '', width: '', }, value: this.props.value, } navContent pointerTimeout componentDidMount() { const { showPointer } = this.props if (showPointer) { const { value } = this.state // @ts-ignore const items = filterDisabled(this.props.items) this.updatePointer(items.findIndex(item => item.id === value)) } } static getDerivedStateFromProps(props, state) { return makeControllable(props, state, 'value') } componentWillUnmount() { clearTimeout(this.pointerTimeout) } handleChange = value => { const { onChange, showPointer } = this.props const items = filterDisabled(this.props.items) if (onChange) { onChange(value) } if (showPointer) { this.updatePointer(items.findIndex(item => item.id === value)) } this.setState({ value }) } // tslint:disable-next-line componentDidUpdate(nextProps) { const { value, showPointer } = nextProps const items = filterDisabled(this.props.items) if (showPointer) { this.updatePointer(items.findIndex(item => item.id === value)) } } updatePointer(index) { clearTimeout(this.pointerTimeout) this.pointerTimeout = setTimeout(() => { if (this.navContent && this.navContent.children.length && index >= 0) { const startPoint = this.navContent.getBoundingClientRect().left const label = this.navContent.children[index].getBoundingClientRect() // TODO: replace by css transition! this.setState({ pointer: { left: `${label.left - startPoint}px`, width: `${label.width}px`, }, }) } }, 20) } render() { const { renderList, pointerPosition, showPointer } = this.props const { pointer } = this.state const items = filterDisabled(this.props.items) return (
{ this.navContent = element }} > {renderList({ ...this.props, state: this.state, handleChange: this.handleChange, list: items, })}
{showPointer && }
) } }