main
js 140 lines 3.42 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @flow
8 */
9
10 import * as React from 'react';
11 import {Fragment, useCallback} from 'react';
12 import Icon from './Icon';
13
14 import styles from './TabBar.css';
15 import Tooltip from './Components/reach-ui/tooltip';
16
17 import type {IconType} from './Icon';
18
19 type TabInfo = {
20 icon: IconType,
21 id: string,
22 label: string,
23 title?: string,
24 };
25
26 export type Props = {
27 currentTab: any,
28 disabled?: boolean,
29 id: string,
30 selectTab: (tabID: any) => void,
31 tabs: Array<TabInfo | null>,
32 type: 'navigation' | 'profiler' | 'settings',
33 };
34
35 export default function TabBar({
36 currentTab,
37 disabled = false,
38 id: groupName,
39 selectTab,
40 tabs,
41 type,
42 }: Props): React.Node {
43 if (!tabs.some(tab => tab !== null && tab.id === currentTab)) {
44 const firstTab = tabs.find(tab => tab !== null) as any as TabInfo;
45 selectTab(firstTab.id);
46 }
47
48 const onChange = useCallback(
49 ({currentTarget}: $FlowFixMe) => selectTab(currentTarget.value),
50 [selectTab],
51 );
52
53 const handleKeyDown = useCallback((event: $FlowFixMe) => {
54 switch (event.key) {
55 case 'ArrowDown':
56 case 'ArrowLeft':
57 case 'ArrowRight':
58 case 'ArrowUp':
59 event.stopPropagation();
60 break;
61 default:
62 break;
63 }
64 }, []);
65
66 let iconSizeClassName;
67 let tabLabelClassName;
68 let tabSizeClassName;
69 switch (type) {
70 case 'navigation':
71 iconSizeClassName = styles.IconSizeNavigation;
72 tabLabelClassName = styles.TabLabelNavigation;
73 tabSizeClassName = styles.TabSizeNavigation;
74 break;
75 case 'profiler':
76 iconSizeClassName = styles.IconSizeProfiler;
77 tabLabelClassName = styles.TabLabelProfiler;
78 tabSizeClassName = styles.TabSizeProfiler;
79 break;
80 case 'settings':
81 iconSizeClassName = styles.IconSizeSettings;
82 tabLabelClassName = styles.TabLabelSettings;
83 tabSizeClassName = styles.TabSizeSettings;
84 break;
85 default:
86 throw Error(`Unsupported type "${type}"`);
87 }
88
89 return (
90 <Fragment>
91 {tabs.map(tab => {
92 if (tab === null) {
93 return <div key="VRule" className={styles.VRule} />;
94 }
95
96 const {icon, id, label, title} = tab;
97
98 let button = (
99 <label
100 className={[
101 tabSizeClassName,
102 disabled ? styles.TabDisabled : styles.Tab,
103 !disabled && currentTab === id ? styles.TabCurrent : '',
104 ].join(' ')}
105 data-testname={`TabBarButton-${id}`}
106 key={id}
107 onKeyDown={handleKeyDown}
108 onMouseDown={() => selectTab(id)}>
109 <input
110 type="radio"
111 className={styles.Input}
112 checked={currentTab === id}
113 disabled={disabled}
114 name={groupName}
115 value={id}
116 onChange={onChange}
117 />
118 <Icon
119 className={`${
120 disabled ? styles.IconDisabled : ''
121 } ${iconSizeClassName}`}
122 type={icon}
123 />
124 <span className={tabLabelClassName}>{label}</span>
125 </label>
126 );
127
128 if (title) {
129 button = (
130 <Tooltip key={id} label={title}>
131 {button}
132 </Tooltip>
133 );
134 }
135
136 return button;
137 })}
138 </Fragment>
139 );
140 }