Last active
June 7, 2022 13:26
-
-
Save natansevero/ae2597d41e39eb2b58019cbb774b7680 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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