Incorrect window reference when used in a new browser window
When using this component inside a new window (e.g., via window.open), there are issues related to resizing.
Root Cause The component currently references the global window object directly. This always points to the main window, not the newly opened one. As a result, event listeners (e.g., for resize) do not behave correctly when the component is rendered in a different window context.
Proposed Solution Allow the component to accept a window prop, enabling consumers to specify which window object the component should use. This would ensure the correct event context is used, especially for resize or similar interactions.
Additional Notes JavaScript execution still runs in the main thread of the original window, but referencing window in code always points to the main window unless explicitly overridden.
Reproduction:
https://codesandbox.io/p/sandbox/zw8dzr
Code in case sandbox stops working
import "./styles.css";
import { Allotment } from "allotment";
import "allotment/dist/style.css";
import {
useState,
useMemo,
useEffect,
PropsWithChildren,
FC,
useLayoutEffect,
} from "react";
import { createPortal } from "react-dom";
function App() {
const [newWindow, setNewWindow] = useState<Window | null>(null);
const open = () => {
const newWindow = window.open(
"about:blank",
"_blank",
`width=1280,height=720`
);
setNewWindow(newWindow);
console.log("new window", newWindow);
};
return (
<div>
This allotment component is in the main window. It works well. Try
resizing.
<Content />
<br />
Open the link to test in a new window. Note: you might need to open this
codesandbox in its own window for styles to load correctly.
<br />
Click top right icon button "Open in a new tab"
<br />
<button onClick={open}>Open</button>
{newWindow && (
<NewWindow newWindow={newWindow}>
Here the allotmenet component does NOT work well. Because the "window"
object used within the component is not the right one.
<Content />
</NewWindow>
)}
</div>
);
}
const Content = () => {
return (
<div style={{ border: "1px dotted red", height: "200px" }}>
<Allotment>
<div>Pane 1</div>
<div>Pane 1</div>
</Allotment>
</div>
);
};
const NewWindow: FC<PropsWithChildren<{ newWindow: any }>> = ({
children,
newWindow,
}) => {
useLayoutEffect(() => {
document.head.querySelectorAll("link, style").forEach((htmlElement) => {
newWindow.document.head.appendChild(htmlElement.cloneNode(true));
});
}, []);
if (!newWindow) {
return null;
}
return createPortal(children, newWindow?.document?.body);
};
export default App;