|
3 | 3 | // Use of this source code is governed by a BSD-style license that can be
|
4 | 4 | // found in the LICENSE file.
|
5 | 5 |
|
| 6 | +import * as i18n from '../../core/i18n/i18n.js'; |
6 | 7 | import * as UI from '../../ui/legacy/legacy.js';
|
| 8 | +import * as SDK from '../../core/sdk/sdk.js'; |
| 9 | +import * as ReactDevTools from '../../third_party/react-devtools/react-devtools.js'; |
7 | 10 |
|
8 |
| -let instance: ReactDevToolsViewImpl; |
| 11 | +import type * as ReactDevToolsTypes from '../../third_party/react-devtools/react-devtools.js'; |
| 12 | +import type * as Common from '../../core/common/common.js'; |
9 | 13 |
|
10 |
| -export class ReactDevToolsViewImpl extends UI.Widget.VBox { |
11 |
| - static instance(): ReactDevToolsViewImpl { |
12 |
| - if (!instance) { |
13 |
| - instance = new ReactDevToolsViewImpl(); |
14 |
| - } |
| 14 | +import {Events, ReactDevToolsModel, type EventTypes} from './ReactDevToolsModel.js'; |
| 15 | + |
| 16 | +const UIStrings = { |
| 17 | + /** |
| 18 | + *@description Title of the React DevTools view |
| 19 | + */ |
| 20 | + title: 'React DevTools', |
| 21 | +}; |
| 22 | +const str_ = i18n.i18n.registerUIStrings('panels/react_devtools/ReactDevToolsView.ts', UIStrings); |
| 23 | +const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_); |
| 24 | + |
| 25 | +export class ReactDevToolsViewImpl extends UI.View.SimpleView { |
| 26 | + private readonly wall: ReactDevToolsTypes.Wall; |
| 27 | + private readonly bridge: ReactDevToolsTypes.Bridge; |
| 28 | + private readonly store: ReactDevToolsTypes.Store; |
| 29 | + private readonly listeners: Set<ReactDevToolsTypes.WallListener> = new Set(); |
| 30 | + |
| 31 | + constructor() { |
| 32 | + super(i18nString(UIStrings.title)); |
| 33 | + |
| 34 | + this.wall = { |
| 35 | + listen: (listener): Function => { |
| 36 | + this.listeners.add(listener); |
| 37 | + |
| 38 | + return (): void => { |
| 39 | + this.listeners.delete(listener); |
| 40 | + }; |
| 41 | + }, |
| 42 | + send: (event, payload): void => this.sendMessage(event, payload), |
| 43 | + }; |
| 44 | + |
| 45 | + // To use the custom Wall we've created, we need to also create our own "Bridge" and "Store" objects. |
| 46 | + this.bridge = ReactDevTools.createBridge(this.wall); |
| 47 | + this.store = ReactDevTools.createStore(this.bridge); |
| 48 | + |
| 49 | + SDK.TargetManager.TargetManager.instance().addModelListener( |
| 50 | + ReactDevToolsModel, |
| 51 | + Events.MessageReceived, |
| 52 | + this.onMessage, |
| 53 | + this, |
| 54 | + ); |
15 | 55 |
|
16 |
| - return instance; |
| 56 | + SDK.TargetManager.TargetManager.instance().addModelListener( |
| 57 | + ReactDevToolsModel, |
| 58 | + Events.Initialized, |
| 59 | + this.initialize, |
| 60 | + this, |
| 61 | + ); |
| 62 | + |
| 63 | + const loaderContainer = document.createElement('div'); |
| 64 | + loaderContainer.setAttribute('style', 'display: flex; flex: 1; justify-content: center; align-items: center'); |
| 65 | + |
| 66 | + const loader = document.createElement('span'); |
| 67 | + loader.classList.add('spinner'); |
| 68 | + |
| 69 | + loaderContainer.appendChild(loader); |
| 70 | + this.contentElement.appendChild(loaderContainer); |
17 | 71 | }
|
18 | 72 |
|
19 |
| - private constructor() { |
20 |
| - super(true, true); |
| 73 | + private initialize(): void { |
| 74 | + // Remove loader |
| 75 | + this.contentElement.removeChildren(); |
| 76 | + |
| 77 | + const usingDarkTheme = window.matchMedia('(prefers-color-scheme: dark)').matches; |
| 78 | + |
| 79 | + this.registerCSSFiles([ReactDevTools.CSS]); |
| 80 | + ReactDevTools.initialize(this.contentElement, { |
| 81 | + bridge: this.bridge, |
| 82 | + store: this.store, |
| 83 | + theme: usingDarkTheme ? 'dark' : 'light', |
| 84 | + }); |
21 | 85 | }
|
22 | 86 |
|
23 |
| - override wasShown(): void { |
24 |
| - super.wasShown(); |
| 87 | + private onMessage(event: Common.EventTarget.EventTargetEvent<EventTypes[Events.MessageReceived]>): void { |
| 88 | + if (!event.data) { |
| 89 | + return; |
| 90 | + } |
25 | 91 |
|
26 |
| - this.render(); |
| 92 | + for (const listener of this.listeners) { |
| 93 | + listener(event.data); |
| 94 | + } |
27 | 95 | }
|
28 | 96 |
|
29 |
| - render(): void { |
30 |
| - return; |
| 97 | + private sendMessage(event: string, payload?: ReactDevToolsTypes.MessagePayload): void { |
| 98 | + for (const model of SDK.TargetManager.TargetManager.instance().models(ReactDevToolsModel, {scoped: true})) { |
| 99 | + void model.sendMessage({event, payload}); |
| 100 | + } |
31 | 101 | }
|
32 | 102 | }
|
0 commit comments