Skip to content

Instantly share code, notes, and snippets.

@khusamov
Created November 28, 2019 18:19
Show Gist options
  • Save khusamov/b62eabbd0a5808635067da9b8e2ec140 to your computer and use it in GitHub Desktop.
Save khusamov/b62eabbd0a5808635067da9b8e2ec140 to your computer and use it in GitHub Desktop.
Паттерн как задавать значения по умолчанию
import React, {Component, ContextType, FC, Fragment, MouseEvent, ReactNode} from 'react';
import {FaTrashAlt} from 'react-icons/all';
import classNames from 'classnames';
import TabPanelContext from '../TabPanel/TabPanelContext';
import ETabType from './ETabType';
import styles from './TabHeader.scss';
interface IRegularProps {
label?: string;
onRemove?: (item: any) => void;
onRemoveIconClick: (item: any) => void;
}
const Regular: FC<IRegularProps> = (
({label, onRemove, onRemoveIconClick}) => (
<Fragment>
{label}
{onRemove && (
<FaTrashAlt
className={styles.removeIcon}
onClick={onRemoveIconClick}
title={`Удалить '${label}'`}
/>
)}
</Fragment>
)
);
interface ITabHeaderProps<T> {
label?: string;
item?: T;
/**
* Тип кнопки вкладки.
* @default ETabType.Regular
*/
type?: ETabType;
}
const classNameTabTypeMap = {
[ETabType.Regular]: styles.Regular,
[ETabType.Space]: styles.Space,
[ETabType.AddButton]: styles.AddButton
};
type TTabHeaderPropsWithDefaults<T> = (
ITabHeaderProps<T>
& Required<Pick<ITabHeaderProps<T>, 'type'>>
& Readonly<{children?: ReactNode}>
);
/**
* Отображение кнопки вкладки в зависимости от типа:
* - Обычная кнопка: название вкладки и кнопка 'Удалить вкладку',
* - Space: пустое пространство,
* - AddButton: кнопка 'Добавить вкладку'.
*/
export default class TabHeader<T = any> extends Component<ITabHeaderProps<T>> {
static contextType = TabPanelContext;
context!: ContextType<typeof TabPanelContext>;
private get propsWithDefault(): TTabHeaderPropsWithDefaults<T> {
return {
...this.props,
type: this.props.type || ETabType.Regular
};
}
public render(): ReactNode {
const {label, type, children, item} = this.propsWithDefault;
const {onRemove} = this.context;
const className = classNames({
[styles.TabHeader]: true,
[classNameTabTypeMap[type]]: true,
[styles.selected]: this.context.activeItem === item
});
return (
<div className={className} onClick={this.onTabHeaderClick}>
{(() => {
switch (type) {
case ETabType.Regular: return <Regular label={label} onRemove={onRemove} onRemoveIconClick={this.onRemoveIconClick}/>;
case ETabType.Space: return null;
case ETabType.AddButton: return children;
default: throw new Error(`Неизвестный тип вкладки '${type}'`);
}
})()}
</div>
);
}
private onTabHeaderClick = (event: MouseEvent<HTMLDivElement>) => {
event.stopPropagation();
const {item} = this.props;
const {onChange} = this.context;
onChange(item);
};
private onRemoveIconClick = (event: MouseEvent<SVGElement>) => {
event.stopPropagation();
const {item} = this.props;
const {onRemove} = this.context;
if (onRemove) onRemove(item);
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment