desktop/plugins/public/hermesdebuggerrn/ChromeDevTools.tsx (84 lines of code) (raw):

/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @format */ import React from 'react'; import {styled, colors, FlexColumn} from 'flipper'; const devToolsNodeId = (url: string) => `hermes-chromedevtools-out-of-react-node-${url.replace(/\W+/g, '-')}`; // TODO: build abstraction of this: T62306732 // TODO: reuse reactdevtools/DevToolsEmbedder for this const TARGET_CONTAINER_ID = 'flipper-out-of-contents-container'; // should be a hook in the future function createDevToolsNode( url: string, marginTop: string | null, ): HTMLElement { const existing = findDevToolsNode(url); if (existing) { return existing; } const wrapper = document.createElement('div'); wrapper.id = devToolsNodeId(url); wrapper.style.height = '100%'; wrapper.style.width = '100%'; const iframe = document.createElement( 'webview', ) as unknown as HTMLIFrameElement; iframe.style.height = '100%'; iframe.style.width = '100%'; // HACK: chrome-devtools:// is blocked by the sandbox but devtools:// isn't for some reason. iframe.src = url.replace(/^chrome-/, ''); wrapper.appendChild(iframe); if (marginTop) { document.getElementById(TARGET_CONTAINER_ID)!.style.marginTop = marginTop; } document.getElementById(TARGET_CONTAINER_ID)!.appendChild(wrapper); return wrapper; } function findDevToolsNode(url: string): HTMLElement | null { return document.querySelector('#' + devToolsNodeId(url)); } function attachDevTools(devToolsNode: HTMLElement) { devToolsNode.style.display = 'block'; document.getElementById(TARGET_CONTAINER_ID)!.style.display = 'block'; document.getElementById(TARGET_CONTAINER_ID)!.parentElement!.style.display = 'block'; document.getElementById(TARGET_CONTAINER_ID)!.parentElement!.style.height = '100%'; } function detachDevTools(devToolsNode: HTMLElement | null) { document.getElementById(TARGET_CONTAINER_ID)!.style.display = 'none'; document.getElementById(TARGET_CONTAINER_ID)!.parentElement!.style.display = 'none'; if (devToolsNode) { devToolsNode.style.display = 'none'; } } const EmptyContainer = styled(FlexColumn)({ height: '100%', width: '100%', justifyContent: 'center', alignItems: 'center', backgroundColor: colors.light02, }); type ChromeDevToolsProps = { url: string; marginTop: string | null; }; export default class ChromeDevTools extends React.Component<ChromeDevToolsProps> { createDevTools(url: string, marginTop: string | null) { const devToolsNode = createDevToolsNode(url, marginTop); attachDevTools(devToolsNode); } hideDevTools(_url: string) { detachDevTools(findDevToolsNode(this.props.url)); } componentDidMount() { this.createDevTools(this.props.url, this.props.marginTop); } componentWillUnmount() { this.hideDevTools(this.props.url); } componentDidUpdate(prevProps: ChromeDevToolsProps) { const oldUrl = prevProps.url; const newUrl = this.props.url; if (oldUrl != newUrl) { this.hideDevTools(oldUrl); this.createDevTools(newUrl, this.props.marginTop); } } render() { return <EmptyContainer />; } }