Make DOM selection binding one-way
Dan committed
Apr 9, 2019 at 01:30 UTC
72eccb465d7f7b4659d002e2a8510423546f0928
2 files changed
+25
-47
shells/browser/shared/src/main.js
+20
-33
@@ -85,12 +85,6 @@ function createPanelIfReactLoaded() {
85
);
86
});
87
88
- // Remember if we should sync the browser DevTools to the React tab.
89
- // We'll only do that if user intentionally chooses a different React component.
90
- bridge.addListener('selectElement', () => {
91
- hasReactSelectionChanged = true;
92
- });
93
-
88
// This flag lets us tip the Store off early that we expect to be profiling.
89
// This avoids flashing a temporary "Profiling not supported" message in the Profiler tab,
90
// after a user has clicked the "reload and profile" button.
@@ -168,51 +162,39 @@ function createPanelIfReactLoaded() {
162
container._hasInitialHTMLBeenCleared = true;
163
}
164
171
- function maybeSetReactSelectionFromBrowser() {
165
+ function setReactSelectionFromBrowser() {
166
// When the user chooses a different node in the browser Elements tab,
167
// copy it over to the hook object so that we can sync the selection.
168
chrome.devtools.inspectedWindow.eval(
175
- // Don't reset selection if it didn't change in Elements tab.
176
- '(window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$0 !== $0)' +
177
- ' ? (window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$0 = $0, true)' +
178
- ' : false',
179
- (didChangeSelection, error) => {
169
+ '(window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$0 = $0, undefined)',
170
+ (_, error) => {
171
if (error) {
172
console.error(error);
182
- } else if (didChangeSelection) {
173
+ } else {
174
bridge.send('syncSelectionFromNativeElementsPanel');
175
}
176
}
177
);
178
}
179
189
- let hasReactSelectionChanged = false;
190
-
191
- function maybeSetBrowserSelectionFromReact() {
192
- // Don't change the browser element selection when navigating away
193
- // from the Components tab if the user didn't change the React selection.
194
- if (!hasReactSelectionChanged) {
180
+ // When the user selects another item in the native Elements tab,
181
+ // select the corresponding React component.
182
+ let isListeningToNativeSelectionChange = false;
183
+ function ensureListeningToNativeSelectionChange() {
184
+ if (isListeningToNativeSelectionChange) {
185
return;
186
}
197
- hasReactSelectionChanged = false;
198
- chrome.devtools.inspectedWindow.eval(
199
- '(window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$0 != null)' +
200
- ' ? (inspect(window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$0), true)' +
201
- ' : false',
202
- (_, error) => {
203
- if (error) {
204
- console.error(error);
205
- }
206
- }
207
- );
187
+ isListeningToNativeSelectionChange = true;
188
+ setReactSelectionFromBrowser();
189
+ chrome.devtools.panels.elements.onSelectionChanged.addListener(() => {
190
+ setReactSelectionFromBrowser();
191
+ });
192
}
193
194
let currentPanel = null;
195
196
chrome.devtools.panels.create('⚛ Components', '', 'panel.html', panel => {
197
panel.onShown.addListener(panel => {
214
- maybeSetReactSelectionFromBrowser();
215
-
198
if (currentPanel === panel) {
199
return;
200
}
@@ -225,9 +207,14 @@ function createPanelIfReactLoaded() {
207
render('components');
208
panel.injectStyles(cloneStyleTags);
209
}
210
+
211
+ // Don't start listening to native selection change
212
+ // until *after* the panel is visible. Otherwise, we'll
213
+ // set the selected element too early and won't scroll
214
+ // to it the first time we open Components panel.
215
+ ensureListeningToNativeSelectionChange();
216
});
217
panel.onHidden.addListener(() => {
230
- maybeSetBrowserSelectionFromReact();
218
// TODO: Stop highlighting and stuff.
219
});
220
});
src/backend/agent.js
+5
-14
@@ -308,22 +308,13 @@ export default class Agent extends EventEmitter {
308
if (renderer == null) {
309
console.warn(`Invalid renderer id "${rendererID}" for element "${id}"`);
310
} else {
311
- // When a different React component is selected, we want to store
312
- // the active DOM node ($0) on the global hook so that content script
313
- // can update the native elements panel to match it.
314
- const node = ((renderer.findNativeByFiberID(id): any): HTMLElement);
315
- if (node !== null) {
316
- // However, we don't want to do it if the current $0 node already
317
- // belongs to this component. In this case we were probably inspecting
318
- // a part of its host subtree, and changing $0 would be disuptive.
319
- const prev$0 = window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$0;
320
- const prev$0ID = this.getIDForNode(prev$0);
321
- if (prev$0ID !== id) {
322
- window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$0 = node;
323
- }
324
- }
311
renderer.selectElement(id);
312
this._bridge.send('selectElement');
313
+ // TODO: If there was a way to change the selected DOM element
314
+ // in native Elements tab without forcing a switch to it, we'd do it here.
315
+ // For now, it doesn't seem like there is a way to do that:
316
+ // https://github.com/bvaughn/react-devtools-experimental/issues/102
317
+ // (Setting $0 doesn't work, and calling inspect() switches the tab.)
318
}
319
};
320