Skip to content

Instantly share code, notes, and snippets.

@DubiousS
Last active July 3, 2019 08:44
Show Gist options
  • Select an option

  • Save DubiousS/4b3aeb43c5ef9bbca2d686ca0ba2c7ff to your computer and use it in GitHub Desktop.

Select an option

Save DubiousS/4b3aeb43c5ef9bbca2d686ca0ba2c7ff to your computer and use it in GitHub Desktop.
import * as React from 'react';
export type ITabIndex = number | string;
export interface ITabsContext {
selectedIndex: ITabIndex;
selectTab(index: ITabIndex): void;
}
export const { Provider, Consumer } = React.createContext<ITabsContext>({
selectedIndex: 0,
selectTab: () => undefined,
});
import cn from 'classnames';
import * as React from 'react';
import { Consumer, Provider } from 'contexts/tab-context';
import styles from './TabsStyles.scss';
import { ITabIndex, ITabsContext } from 'contexts/tab-context';
interface ITabsProps {
children: React.ReactNode;
initalIndex?: ITabIndex;
}
interface IPanelProps {
index: number;
enableReinitialize?: boolean;
hidden?: boolean;
children: React.ReactNode;
className?: string;
}
interface IListProps {
children: React.ReactNode;
className?: string;
}
interface ITabProps {
index: number;
className?: string;
activeClassName?: string;
hidden?: boolean;
disabledClassName?: string;
disabled?: boolean;
children: React.ReactNode;
}
interface ITabsState {
selectedTab: ITabIndex;
}
class TabsComponent extends React.Component<ITabsProps, ITabsState> {
constructor(props: ITabsProps) {
super(props);
this.state = {
selectedTab: this.props.initalIndex,
};
}
public static defaultProps = {
initalIndex: 0,
};
public static Tab: React.FC<ITabProps> = ({
children,
index,
activeClassName,
disabledClassName,
disabled,
hidden,
className,
}): React.ReactElement<ITabProps> => (
<Consumer>
{({ selectedIndex, selectTab }: ITabsContext) => {
const isActive = selectedIndex === index;
return !hidden && (
<ul
className={cn(styles.tabsTab, {
[className]: className,
[activeClassName]: !disabled && isActive,
[disabledClassName]: disabled,
[styles.tabsTabActive]: !disabled && isActive,
[styles.tabsTabDisabled]: disabled,
})}
onClick={() => !disabled && selectTab(index)}
>
{children}
</ul>
);
}}
</Consumer>
)
public static List: React.FC<IListProps> = ({
children,
className,
}): React.ReactElement<IListProps> => (
<li
className={cn(styles.tabsList, {
[className]: className,
})}
>
{children}
</li>
)
public static Panel: React.FC<IPanelProps> = ({
index,
children,
className,
enableReinitialize,
hidden,
}): React.ReactElement<ITabsState> => (
<Consumer>
{({ selectedIndex }: ITabsContext) => {
const isActive = index === selectedIndex && !hidden;
return !hidden && !enableReinitialize
? (
<span
className={cn({
[className]: className,
[styles.tabsPanelHidden]: !isActive,
})}
>
{children}
</span>
)
: isActive && (
<span
className={cn({
[className]: className,
})}
>
{children}
</span>
);
}}
</Consumer>
)
private selectTab = (index: ITabIndex) => {
this.setState({
selectedTab: index,
});
}
public render(): React.ReactNode {
return (
<Provider
value={{
selectedIndex: this.state.selectedTab,
selectTab: this.selectTab,
}}
>
{this.props.children}
</Provider>
);
}
}
TabsComponent.List.displayName = 'TabList';
TabsComponent.Tab.displayName = 'Tab';
TabsComponent.Tab.defaultProps = {
disabled: false,
hidden: false,
className: '',
activeClassName: '',
disabledClassName: '',
};
TabsComponent.Panel.displayName = 'TabPanel';
TabsComponent.Panel.defaultProps = {
className: '',
enableReinitialize: false,
hidden: false,
};
export default TabsComponent;
@import '~assets/styles/variables';
@import '~assets/styles/color';
.tabs {
&List {
display: flex;
}
&PanelHidden {
position: fixed;
width: 0;
height: 0;
opacity: 0;
}
&Tab {
display: block;
border-bottom: 1px solid transparent;
transition: $defaultAnimationTime;
padding: 5px;
cursor: pointer;
&Active {
border-bottom: 1px solid $two;
}
&Disabled {
opacity: 0.8;
cursor: auto;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment