import "./tabs.scss"; import React, { DOMAttributes } from "react"; import { autobind, cssNames } from "../../utils"; import { Icon } from "../icon"; const TabsContext = React.createContext({}); interface TabsContextValue { autoFocus?: boolean; value?: D; onChange?(value: D): void; } type Omit = Pick> export interface TabsProps extends TabsContextValue, Omit, "onChange"> { className?: string; center?: boolean; wrap?: boolean; scrollable?: boolean; } export class Tabs extends React.PureComponent { public elem: HTMLElement; @autobind() protected bindRef(elem: HTMLElement): void { this.elem = elem; } render(): JSX.Element { const { center, wrap, onChange, value, autoFocus, scrollable = true, ...elemProps } = this.props; let { className } = this.props; className = cssNames("Tabs", className, { "center": center, "wrap": wrap, "scrollable": scrollable, }); return (
); } } export interface TabProps extends DOMAttributes { className?: string; active?: boolean; disabled?: boolean; icon?: React.ReactNode | string; // material-ui name or custom icon label?: React.ReactNode; value: D; } export class Tab extends React.PureComponent { static contextType = TabsContext; public context: TabsContextValue; public elem: HTMLElement; get isActive(): boolean { const { active, value } = this.props; return typeof active === "boolean" ? active : this.context.value === value; } focus(): void { this.elem.focus(); } scrollIntoView(): void { this.elem.scrollIntoView({ behavior: "smooth", inline: "center", }); } @autobind() onClick(evt: React.MouseEvent): void { const { value, active, disabled, onClick } = this.props; const { onChange } = this.context; if (disabled || active) { return; } if (onClick) { onClick(evt); } if (onChange) { onChange(value); } } @autobind() onFocus(evt: React.FocusEvent): void { const { onFocus } = this.props; if (onFocus) { onFocus(evt); } this.scrollIntoView(); } @autobind() onKeyDown(evt: React.KeyboardEvent): void { const ENTER_KEY = evt.keyCode === 13; const SPACE_KEY = evt.keyCode === 32; if (SPACE_KEY || ENTER_KEY) { this.elem.click(); } const { onKeyDown } = this.props; if (onKeyDown) { onKeyDown(evt); } } componentDidMount(): void { if (this.isActive && this.context.autoFocus) { this.focus(); } } @autobind() protected bindRef(elem: HTMLElement): void { this.elem = elem; } render(): JSX.Element { const { active: _active, disabled, icon, label, value: _value, ...elemProps } = this.props; let { className } = this.props; className = cssNames("Tab flex gaps align-center", className, { "active": this.isActive, "disabled": disabled, }); return (
{typeof icon === "string" ? : icon}
{label}
); } }