Use generics to better type TabbedView (#10726)

This commit is contained in:
Michael Telatynski 2023-04-27 12:55:29 +01:00 committed by GitHub
parent fcf2fe2c1d
commit a629ce3a53
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 56 additions and 52 deletions

View file

@ -29,7 +29,7 @@ import { RovingAccessibleButton, RovingTabIndexProvider } from "../../accessibil
/**
* Represents a tab for the TabbedView.
*/
export class Tab {
export class Tab<T extends string> {
/**
* Creates a new tab.
* @param {string} id The tab's ID.
@ -39,7 +39,7 @@ export class Tab {
* @param {string} screenName The screen name to report to Posthog.
*/
public constructor(
public readonly id: string,
public readonly id: T,
public readonly label: string,
public readonly icon: string | null,
public readonly body: React.ReactNode,
@ -52,20 +52,20 @@ export enum TabLocation {
TOP = "top",
}
interface IProps {
tabs: NonEmptyArray<Tab>;
initialTabId?: string;
interface IProps<T extends string> {
tabs: NonEmptyArray<Tab<T>>;
initialTabId?: T;
tabLocation: TabLocation;
onChange?: (tabId: string) => void;
onChange?: (tabId: T) => void;
screenName?: ScreenName;
}
interface IState {
activeTabId: string;
interface IState<T extends string> {
activeTabId: T;
}
export default class TabbedView extends React.Component<IProps, IState> {
public constructor(props: IProps) {
export default class TabbedView<T extends string> extends React.Component<IProps<T>, IState<T>> {
public constructor(props: IProps<T>) {
super(props);
const initialTabIdIsValid = props.tabs.find((tab) => tab.id === props.initialTabId);
@ -78,7 +78,7 @@ export default class TabbedView extends React.Component<IProps, IState> {
tabLocation: TabLocation.LEFT,
};
private getTabById(id: string): Tab | undefined {
private getTabById(id: T): Tab<T> | undefined {
return this.props.tabs.find((tab) => tab.id === id);
}
@ -87,7 +87,7 @@ export default class TabbedView extends React.Component<IProps, IState> {
* @param {Tab} tab the tab to show
* @private
*/
private setActiveTab(tab: Tab): void {
private setActiveTab(tab: Tab<T>): void {
// make sure this tab is still in available tabs
if (!!this.getTabById(tab.id)) {
if (this.props.onChange) this.props.onChange(tab.id);
@ -97,7 +97,7 @@ export default class TabbedView extends React.Component<IProps, IState> {
}
}
private renderTabLabel(tab: Tab): JSX.Element {
private renderTabLabel(tab: Tab<T>): JSX.Element {
const isActive = this.state.activeTabId === tab.id;
const classes = classNames("mx_TabbedView_tabLabel", {
mx_TabbedView_tabLabel_active: isActive,
@ -130,11 +130,11 @@ export default class TabbedView extends React.Component<IProps, IState> {
);
}
private getTabId(tab: Tab): string {
private getTabId(tab: Tab<T>): string {
return `mx_tabpanel_${tab.id}`;
}
private renderTabPanel(tab: Tab): React.ReactNode {
private renderTabPanel(tab: Tab<T>): React.ReactNode {
const id = this.getTabId(tab);
return (
<div className="mx_TabbedView_tabPanel" key={id} id={id} aria-labelledby={`${id}_label`}>