import * as anime from "animejs"; import * as classNames from "classnames"; import * as _ from "lodash"; import * as React from "react"; import { Sprite, SpriteType } from "../Sprite"; export enum TabType { Slider = "Slider", Bar = "Bar", } interface TabItem { id: string; text?: string; /** * A is used when rendering tabs * as a `Bar` type */ sprite?: SpriteType; } interface ITabsProps { /** Required */ type: TabType; items: TabItem[]; /** Optional */ initialTab?: TabItem; onTabChange?: (tab: TabItem) => void; } interface ITabsState { activeTab: TabItem; } const defaultTabsState: ITabsState = { activeTab: null, } export class Tabs extends React.PureComponent { public state: ITabsState = defaultTabsState; constructor(props: ITabsProps) { super(props); // set `activeTab` to be the first tab unless an initial tab is provided this.state.activeTab = props.initialTab || _.first(props.items); } public componentDidUpdate(prevProps: ITabsProps, prevState: ITabsState) { if (!_.isEqual(prevState.activeTab, this.state.activeTab)) { // update slides if (this.props.type === TabType.Slider) { this.slideToTab(this.state.activeTab.id); } if (this.props.onTabChange) { this.props.onTabChange(this.state.activeTab); } } } public render() { return (
{this.props.items.map((tab: TabItem) => { return (
this.setState({ activeTab: tab })} > {tab.sprite && (
)} {tab.text && (
{tab.text}
)}
); })} {this.props.type === TabType.Slider && (
{this.state.activeTab.text}
)}
); } private isTabActive = (tabItemId: string): boolean => { return this.state.activeTab.id === tabItemId; } private slideToTab = (tabItemId: string) => { anime.remove(".tabs__slider"); anime({ targets: ".tabs__slider", elasticity: 0, duration: 225, // TODO: Remove this hardcoded value which accounts for parent padding // @ts-ignore translateX: document.querySelector(".tabs__item--active").offsetLeft - 2 }); } }