Use @reach tooltips for TabBar, cleanup supports-profiling subscription
Brian Vaughn committed
May 22, 2019 at 18:44 UTC
f14a2fd05cfb2d7fc140f1f59e1fd580c25b6a27
3 files changed
+66
-64
src/devtools/store.js
+2
-1
@@ -865,8 +865,9 @@ export default class Store extends EventEmitter {
865
if (hasOwnerMetadata) {
866
this._hasOwnerMetadata = true;
867
}
868
- if (supportsProfiling) {
868
+ if (!this._supportsProfiling && supportsProfiling) {
869
this._supportsProfiling = true;
870
+ this.emit('supportsProfiling');
871
}
872
}
873
);
src/devtools/views/DevTools.js
+16
-28
@@ -5,7 +5,7 @@
5
import '@reach/menu-button/styles.css';
6
import '@reach/tooltip/styles.css';
7
8
-import React, { useEffect, useState } from 'react';
8
+import React, { useMemo, useState } from 'react';
9
import Store from '../store';
10
import { BridgeContext, StoreContext } from './context';
11
import Components from './Components/Components';
@@ -18,6 +18,7 @@ import ViewElementSourceContext from './Components/ViewElementSourceContext';
18
import { ProfilerContextController } from './Profiler/ProfilerContext';
19
import { ModalDialogContextController } from './ModalDialog';
20
import ReactLogo from './ReactLogo';
21
+import { useSubscription } from './hooks';
22
23
import styles from './DevTools.css';
24
@@ -71,8 +72,7 @@ const settingsTab = {
72
title: 'React Settings',
73
};
74
74
-const tabsWithProfiler = [componentsTab, profilerTab, settingsTab];
75
-const tabsWithoutProfiler = [componentsTab, settingsTab];
75
+const tabs = [componentsTab, profilerTab, settingsTab];
76
77
export default function DevTools({
78
bridge,
@@ -92,27 +92,19 @@ export default function DevTools({
92
setTab(overrideTab);
93
}
94
95
- const [supportsProfiling, setSupportsProfiling] = useState(
96
- store.supportsProfiling
95
+ const supportsProfilingSubscription = useMemo(
96
+ () => ({
97
+ getCurrentValue: () => store.supportsProfiling,
98
+ subscribe: (callback: Function) => {
99
+ store.addListener('supportsProfiling', callback);
100
+ return () => store.removeListener('supportsProfiling', callback);
101
+ },
102
+ }),
103
+ [store]
104
+ );
105
+ const supportsProfiling = useSubscription<boolean, Store>(
106
+ supportsProfilingSubscription
107
);
98
-
99
- // Show/hide the "Profiler" button depending on if profiling is supported.
100
- useEffect(() => {
101
- if (supportsProfiling !== store.supportsProfiling) {
102
- setSupportsProfiling(store.supportsProfiling);
103
- }
104
-
105
- const handleRoots = () => {
106
- if (supportsProfiling !== store.supportsProfiling) {
107
- setSupportsProfiling(store.supportsProfiling);
108
- }
109
- };
110
-
111
- store.addListener('roots', handleRoots);
112
- return () => {
113
- store.removeListener('roots', handleRoots);
114
- };
115
- }, [store, supportsProfiling]);
108
109
return (
110
<BridgeContext.Provider value={bridge}>
@@ -140,11 +132,7 @@ export default function DevTools({
132
id="DevTools"
133
selectTab={setTab}
134
size="large"
143
- tabs={
144
- supportsProfiling
145
- ? tabsWithProfiler
146
- : tabsWithoutProfiler
147
- }
135
+ tabs={tabs}
136
/>
137
</div>
138
)}
src/devtools/views/TabBar.js
+48
-35
@@ -2,9 +2,11 @@
2
3
import classNames from 'classnames';
4
import React, { Fragment, useCallback } from 'react';
5
+import Tooltip from '@reach/tooltip';
6
import Icon from './Icon';
7
8
import styles from './TabBar.css';
9
+import tooltipStyles from './Tooltip.css';
10
11
import type { IconType } from './Icon';
12
@@ -59,42 +61,53 @@ export default function TabBar({
61
62
return (
63
<Fragment>
62
- {tabs.map(({ icon, id, label, title }) => (
63
- <label
64
- className={classNames(
65
- tabClassName,
66
- disabled ? styles.TabDisabled : styles.Tab,
67
- !disabled && currentTab === id ? styles.TabCurrent : null
68
- )}
69
- key={id}
70
- onKeyDown={handleKeyDown}
71
- onMouseDown={() => selectTab(id)}
72
- title={title || label}
73
- >
74
- <input
75
- type="radio"
76
- className={styles.Input}
77
- checked={currentTab === id}
78
- disabled={disabled}
79
- name={groupName}
80
- value={id}
81
- onChange={onChange}
82
- />
83
- <Icon
84
- className={`${disabled ? styles.IconDisabled : ''} ${
85
- size === 'large' ? styles.IconSizeLarge : styles.IconSizeSmall
86
- }`}
87
- type={icon}
88
- />
89
- <span
90
- className={
91
- size === 'large' ? styles.TabLabelLarge : styles.TabLabelSmall
92
- }
64
+ {tabs.map(({ icon, id, label, title }) => {
65
+ let button = (
66
+ <label
67
+ className={classNames(
68
+ tabClassName,
69
+ disabled ? styles.TabDisabled : styles.Tab,
70
+ !disabled && currentTab === id ? styles.TabCurrent : null
71
+ )}
72
+ key={id}
73
+ onKeyDown={handleKeyDown}
74
+ onMouseDown={() => selectTab(id)}
75
>
94
- {label}
95
- </span>
96
- </label>
97
- ))}
76
+ <input
77
+ type="radio"
78
+ className={styles.Input}
79
+ checked={currentTab === id}
80
+ disabled={disabled}
81
+ name={groupName}
82
+ value={id}
83
+ onChange={onChange}
84
+ />
85
+ <Icon
86
+ className={`${disabled ? styles.IconDisabled : ''} ${
87
+ size === 'large' ? styles.IconSizeLarge : styles.IconSizeSmall
88
+ }`}
89
+ type={icon}
90
+ />
91
+ <span
92
+ className={
93
+ size === 'large' ? styles.TabLabelLarge : styles.TabLabelSmall
94
+ }
95
+ >
96
+ {label}
97
+ </span>
98
+ </label>
99
+ );
100
+
101
+ if (title) {
102
+ button = (
103
+ <Tooltip className={tooltipStyles.Tooltip} label={title}>
104
+ {button}
105
+ </Tooltip>
106
+ );
107
+ }
108
+
109
+ return button;
110
+ })}
111
</Fragment>
112
);
113
}