/** * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ import "./tabs.scss"; import React, { DOMAttributes } from "react"; import { boundMethod, cssNames } from "../../utils"; import { Icon } from "../icon"; const TabsContext = React.createContext({}); interface TabsContextValue { autoFocus?: boolean; withBorder?: 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; @boundMethod protected bindRef(elem: HTMLElement) { this.elem = elem; } render() { const { center, wrap, onChange, value, autoFocus, scrollable = true, withBorder, ...elemProps } = this.props; const className = cssNames("Tabs", this.props.className, { center, wrap, scrollable, withBorder, }); return (
); } } export interface TabProps extends DOMAttributes { id?: string; 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; declare context: TabsContextValue; public ref = React.createRef(); get isActive() { const { active, value } = this.props; return typeof active === "boolean" ? active : this.context.value === value; } focus() { this.ref.current?.focus(); } scrollIntoView() { this.ref.current?.scrollIntoViewIfNeeded(); } @boundMethod onClick(evt: React.MouseEvent) { const { value, active, disabled, onClick } = this.props; if (disabled || active) { return; } onClick?.(evt); this.context.onChange?.(value); } @boundMethod onFocus(evt: React.FocusEvent) { this.props.onFocus?.(evt); this.scrollIntoView(); } @boundMethod onKeyDown(evt: React.KeyboardEvent) { if (evt.key === " " || evt.key === "Enter") { this.ref.current?.click(); } this.props.onKeyDown?.(evt); } componentDidMount() { if (this.isActive && this.context.autoFocus) { this.focus(); } } render() { const { active, disabled, icon, label, value, ...elemProps } = this.props; let { className } = this.props; className = cssNames("Tab flex gaps align-center", className, { "active": this.isActive, disabled, }); return (
{typeof icon === "string" ? : icon}
{label}
); } }