Skip to content

Instantly share code, notes, and snippets.

@natansevero
Last active June 7, 2022 13:26
Show Gist options
  • Save natansevero/ae2597d41e39eb2b58019cbb774b7680 to your computer and use it in GitHub Desktop.
Save natansevero/ae2597d41e39eb2b58019cbb774b7680 to your computer and use it in GitHub Desktop.
interface Props {
title: string; // The title of the popout window
closeWindow: () => void; // Callback to close the popout
}
interface State {
externalWindow: Window | null; // The popout window
containerElement: HTMLElement | null; // The root element of the popout window
}
// link do post
// https://blog.scottlogic.com/2019/10/29/popout-windows-in-react.html
class Popout extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
externalWindow: null,
containerElement: null
};
}
// When we create this component, open a new window
public componentDidMount() {
const features = 'width=800, height=500, left=300, top=200';
const externalWindow = window.open('', '', features);
let containerElement = null;
if (externalWindow) {
containerElement = externalWindow.document.createElement('div');
externalWindow.document.body.appendChild(containerElement);
// Copy the app's styles into the new window
const stylesheets = Array.from(document.styleSheets);
stylesheets.forEach(stylesheet => {
const css = stylesheet as CSSStyleSheet;
if (stylesheet.href) {
const newStyleElement = document.createElement('link');
newStyleElement.rel = 'stylesheet';
newStyleElement.href = stylesheet.href;
externalWindow.document.head.appendChild(newStyleElement);
} else if (css && css.cssRules && css.cssRules.length > 0) {
const newStyleElement = document.createElement('style');
Array.from(css.cssRules).forEach(rule => {
newStyleElement.appendChild(document.createTextNode(rule.cssText));
});
externalWindow.document.head.appendChild(newStyleElement);
}
});
// eslint-disable-next-line react/destructuring-assignment
externalWindow.document.title = this.props.title;
// Make sure the window closes when the component unloads
externalWindow.addEventListener('beforeunload', () => {
// eslint-disable-next-line react/destructuring-assignment
this.props.closeWindow();
});
}
this.setState({
externalWindow,
containerElement
});
}
// Make sure the window closes when the component unmounts
public componentWillUnmount() {
// eslint-disable-next-line react/destructuring-assignment
if (this.state.externalWindow) {
// eslint-disable-next-line react/destructuring-assignment
this.state.externalWindow.close();
}
}
public render() {
// eslint-disable-next-line react/destructuring-assignment
if (!this.state.containerElement) {
return null;
}
// Render this component's children into the root element of the popout window
return ReactDOM.createPortal(
// eslint-disable-next-line react/destructuring-assignment
this.props.children,
// eslint-disable-next-line react/destructuring-assignment
this.state.containerElement
);
}
}
interface Props1 {
title?: string; // The title of the popout window
}
interface State1 {
showPopout: boolean;
}
class ToggleWindow extends React.Component<Props1, State1> {
// We need a state field to govern whether the popout is shown or not
constructor(props: any) {
super(props);
this.state = {
showPopout: false
};
}
// This sets the above state variable
// eslint-disable-next-line react/sort-comp
private setPopoutOpen(open: boolean) {
this.setState({
showPopout: open
});
}
// This sets the above state variable
// eslint-disable-next-line react/sort-comp
private setPopoutOpen2() {
// eslint-disable-next-line react/destructuring-assignment
this.setState((state: any) => ({
showPopout: !state.showPopout
}));
}
// When this component is unloaded, make sure we close the popout
public componentDidMount() {
window.addEventListener('beforeunload', () => {
this.setPopoutOpen(false);
});
}
// This returns the HTML for the popout, or null if the popout isn't visible
private getPopout() {
// eslint-disable-next-line react/destructuring-assignment
if (!this.state.showPopout) {
return null;
}
return (
<Popout
title="Your Popout Title"
closeWindow={() => this.setPopoutOpen(false)}
>
<div>YOUR POPOUT CONTENT HERE</div>
{/* eslint-disable-next-line react/destructuring-assignment */}
{this.props.children}
<Button>aaaaaa</Button>
</Popout>
);
}
// Render the popout and a button to show / hide it
public render() {
return (
<Box
sx={{
bottom: 0,
right: 100,
zIndex: 11,
position: 'absolute',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
p: 2
}}
>
{this.getPopout()}
<button type="button" onClick={() => this.setPopoutOpen2()}>
toggle popout
</button>
</Box>
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment