1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import React, { useEffect, useRef } from 'react';
6 import { Tabs, Tab, List, ListItem, StyleRulesCallback, withStyles } from '@material-ui/core';
7 import { WithStyles } from '@material-ui/core';
8 import classNames from 'classnames';
9 import { ArvadosTheme } from 'common/custom-theme';
11 type TabbedListClasses = 'root' | 'tabs' | 'list' | 'listItem';
13 const tabbedListStyles: StyleRulesCallback<TabbedListClasses> = (theme: ArvadosTheme) => ({
18 backgroundColor: theme.palette.background.paper,
22 borderBottom: '1px solid lightgrey',
32 type TabPanelProps = {
33 children: React.ReactNode;
38 type TabbedListProps<T> = {
39 tabbedListContents: Record<string, T[]>;
40 injectedStyles?: string;
41 selectedIndex?: number;
43 handleSelect?: (selection: T) => React.MouseEventHandler<HTMLElement> | undefined;
44 renderListItem?: (item: T) => React.ReactNode;
45 handleTabChange?: (event: React.SyntheticEvent, newValue: number) => void;
48 export const TabbedList = withStyles(tabbedListStyles)(<T, _>({ tabbedListContents, selectedIndex, selectedTab, injectedStyles, classes, handleSelect, renderListItem, handleTabChange }: TabbedListProps<T> & WithStyles<TabbedListClasses>) => {
49 const tabNr = selectedTab || 0;
50 const listRefs = useRef<HTMLDivElement[]>([]);
51 const tabLabels = Object.keys(tabbedListContents);
54 if (selectedIndex !== undefined && listRefs.current[selectedIndex]) {
55 listRefs.current[selectedIndex].scrollIntoView({ behavior: 'smooth', block: 'center' });
60 <div className={classNames(classes.root, injectedStyles)}>
61 <div className={classes.tabs}>
64 onChange={handleTabChange}
67 {tabLabels.map((label) => (
76 <List className={classes.list}>
77 {tabbedListContents[tabLabels[tabNr]].map((item, i) => (
78 <div ref={(el) => { if (!!el) listRefs.current[i] = el}}>
80 className={classes.listItem}
81 selected={i === selectedIndex}
82 onClick={handleSelect && handleSelect(item)}
84 {renderListItem ? renderListItem(item) : JSON.stringify(item)}
94 const TabPanel = ({ children, value, index }: TabPanelProps) => {
95 return <div hidden={value !== index}>{value === index && children}</div>;