@samitouri / QOS-React / commits / 4a301bd0e0

Sync DevTools Elements and Components tabs

Dan Abramov committed Apr 8, 2019 at 20:41 UTC 4a301bd0e0457542994d0064dfa7687dd9191be3
2 files changed +57 -2
shells/browser/shared/src/main.js
+34 -2
@@ -162,10 +162,43 @@ function createPanelIfReactLoaded() {
162 container._hasInitialHTMLBeenCleared = true;
163 }
164
165 + function maybeSetReactSelectionFromBrowser() {
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(
169 + // Don't reset selection if it didn't change in Elements tab.
170 + '(window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$0 !== $0)' +
171 + ' ? (window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$0 = $0, true)' +
172 + ' : false',
173 + (didChangeSelection, error) => {
174 + if (error) {
175 + console.error(error);
176 + } else if (didChangeSelection) {
177 + bridge.send('syncSelectionFromBrowserTools');
178 + }
179 + }
180 + );
181 + }
182 +
183 + function maybeSetBrowserSelectionFromReact() {
184 + chrome.devtools.inspectedWindow.eval(
185 + '(window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$0 != null)' +
186 + ' ? (inspect(window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$0), true)' +
187 + ' : false',
188 + (didChangeSelection, error) => {
189 + if (error) {
190 + console.error(error);
191 + }
192 + }
193 + );
194 + }
195 +
196 let currentPanel = null;
197
198 chrome.devtools.panels.create('⚛ Components', '', 'panel.html', panel => {
199 panel.onShown.addListener(panel => {
200 + maybeSetReactSelectionFromBrowser();
201 +
202 if (currentPanel === panel) {
203 return;
204 }
@@ -178,10 +211,9 @@ function createPanelIfReactLoaded() {
211 render('components');
212 panel.injectStyles(cloneStyleTags);
213 }
181 -
182 - // TODO: When the user switches to the panel, check for an Elements tab selection.
214 });
215 panel.onHidden.addListener(() => {
216 + maybeSetBrowserSelectionFromReact();
217 // TODO: Stop highlighting and stuff.
218 });
219 });
src/backend/agent.js
+23
@@ -87,6 +87,10 @@ export default class Agent extends EventEmitter {
87 bridge.addListener('startProfiling', this.startProfiling);
88 bridge.addListener('stopInspectingDOM', this.stopInspectingDOM);
89 bridge.addListener('stopProfiling', this.stopProfiling);
90 + bridge.addListener(
91 + 'syncSelectionFromBrowserTools',
92 + this.syncSelectionFromBrowserTools
93 + );
94 bridge.addListener('shutdown', this.shutdown);
95 bridge.addListener('viewElementSource', this.viewElementSource);
96
@@ -292,6 +296,14 @@ export default class Agent extends EventEmitter {
296 if (renderer == null) {
297 console.warn(`Invalid renderer id "${rendererID}" for element "${id}"`);
298 } else {
299 + // Update the active DOM node on the global hook object.
300 + // The content script will read this to update window.$0
301 + // when we switch tabs.
302 + let node: HTMLElement | null = null;
303 + node = ((renderer.findNativeByFiberID(id): any): HTMLElement);
304 + if (node !== null) {
305 + window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$0 = node;
306 + }
307 this._bridge.send('selectElement', renderer.selectElement(id));
308 }
309 };
@@ -362,6 +374,17 @@ export default class Agent extends EventEmitter {
374 }
375 }
376
377 + syncSelectionFromBrowserTools = () => {
378 + const target = window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$0;
379 + if (target == null) {
380 + return;
381 + }
382 + const id = this.getIDForNode(target);
383 + if (id !== null) {
384 + this._bridge.send('selectFiber', id);
385 + }
386 + };
387 +
388 shutdown = () => {
389 this.emit('shutdown');
390 };