[devtools-shell] layout options for testing (#33516)

## Summary

This PR adds a 'Layout' selector to the devtools shell main example, as
well as a resizable split pane, allowing more realistic testing of how
the devtools behaves when used in a vertical or horizontal layout and at
different sizes (e.g. when resizing the Chrome Dev Tools pane).

## How did you test this change?



https://github.com/user-attachments/assets/81179413-7b46-47a9-bc52-4f7ec414e8be
This commit is contained in:
James Friend 2025-06-13 10:25:04 -04:00 committed by GitHub
parent a00ca6f6b5
commit ed023cfc73
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,28 +1,61 @@
<!doctype html>
<html>
<head>
<meta charset="utf8">
<title>React DevTools</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
#panes {
display: grid;
height: 100%;
width: 100%;
position: relative;
}
#divider {
position: absolute;
z-index: 10000002;
background-color: #ccc;
transition: background-color 0.2s;
}
#divider:hover,
#divider.dragging {
background-color: #aaa;
}
#divider.horizontal-divider {
width: 100%;
height: 5px;
cursor: row-resize;
}
#divider.vertical-divider {
width: 5px;
height: 100%;
cursor: col-resize;
}
#target {
flex: 1;
height: 100%;
width: 100%;
border: none;
}
#devtools {
height: 400px;
max-height: 50%;
height: 100%;
width: 100%;
overflow: hidden;
z-index: 10000001;
}
body {
display: flex;
height: 100vh;
width: 100vw;
contain: strict;
flex-direction: column;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,
@ -30,6 +63,7 @@
font-size: 12px;
line-height: 1.5;
}
.optionsRow {
width: 100%;
display: flex;
@ -38,11 +72,13 @@
border-bottom: 1px solid lightblue;
box-sizing: border-box;
}
.optionsRowSpacer {
flex: 1;
}
</style>
</head>
<body>
<div class="optionsRow">
<button id="mountButton">Unmount test app</button>
@ -56,19 +92,122 @@
|
<a href="/perf-regression.html">perf regression tests</a>
</span>
<label style="margin-left: 4px">
Layout:
<select id="layout">
<option value="leftright">Left/Right Split</option>
<option value="topbottom">Top/Bottom Split</option>
</select></label>
</div>
<div id="panes">
<!-- React test app (shells/dev/app) is injected here -->
<!-- DevTools backend (shells/dev/src) is injected here -->
<!-- global "hook" is defined on the iframe's contentWindow -->
<iframe id="target"></iframe>
<!-- Draggable divider between panes -->
<div id="divider"></div>
<!-- DevTools frontend UI (shells/dev/src) renders here -->
<div id="devtools"></div>
</div>
<!-- This script installs the hook, injects the backend, and renders the DevTools UI -->
<!-- In DEV mode, this file is served by the Webpack dev server -->
<!-- For production builds, it's built by Webpack and uploaded from the local file system -->
<script src="dist/app-devtools.js"></script>
<script type="module">
let layoutType = 'leftright';
let splitRatio = 0.5;
let isDragging = false;
// handle layout changes
const layout = document.getElementById('layout');
function setLayout(layoutType, splitRatio) {
const panes = document.getElementById('panes');
if (layoutType === 'topbottom') {
panes.style.gridTemplateColumns = '100%'; // Full width for each row
panes.style.gridTemplateRows = `${splitRatio * 100}% ${(1 - splitRatio) * 100}%`;
} else if (layoutType === 'leftright') {
panes.style.gridTemplateRows = '100%'; // Full height for each column
panes.style.gridTemplateColumns = `${splitRatio * 100}% ${(1 - splitRatio) * 100}%`;
}
}
layout.addEventListener('change', () => {
layoutType = layout.value;
setLayout(layoutType, splitRatio);
updateDividerPosition(); // Ensure divider updates when layout changes
});
// handle changing the split ratio
const divider = document.getElementById('divider');
function updateDividerPosition() {
if (layoutType === 'topbottom') {
// For top/bottom layout, divider should be horizontal (spanning across)
divider.className = 'horizontal-divider';
divider.style.top = `calc(${splitRatio * 100}% - 2.5px)`;
divider.style.left = '0';
} else {
// For left/right layout, divider should be vertical (spanning down)
divider.className = 'vertical-divider';
divider.style.left = `calc(${splitRatio * 100}% - 2.5px)`;
divider.style.top = '0';
}
}
// Add event listeners for dragging
divider.addEventListener('mousedown', (e) => {
isDragging = true;
divider.classList.add('dragging');
// Disable pointer events on the iframe to prevent it from capturing mouse events
const iframe = document.getElementById('target');
iframe.style.pointerEvents = 'none';
e.preventDefault(); // Prevent text selection during drag
});
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
const panes = document.getElementById('panes');
const rect = panes.getBoundingClientRect();
if (layoutType === 'topbottom') {
// Calculate new split ratio based on vertical position
const newRatio = Math.max(0.1, Math.min(0.9, (e.clientY - rect.top) / rect.height));
splitRatio = newRatio;
} else {
// Calculate new split ratio based on horizontal position
const newRatio = Math.max(0.1, Math.min(0.9, (e.clientX - rect.left) / rect.width));
splitRatio = newRatio;
}
// Update layout and divider position
setLayout(layoutType, splitRatio);
updateDividerPosition();
});
document.addEventListener('mouseup', () => {
if (isDragging) {
isDragging = false;
divider.classList.remove('dragging');
// Re-enable pointer events on the iframe
const iframe = document.getElementById('target');
iframe.style.pointerEvents = 'auto';
}
});
// Initialize
setLayout(
layoutType,
splitRatio,
);
updateDividerPosition();
</script>
</body>
</html>