1
- import React from 'react' ;
2
- import { createRoot } from 'react-dom/client' ;
3
- import PropTypes from 'prop-types' ;
1
+ import React , { PropsWithChildren } from 'react' ;
2
+ import { createRoot , Root } from 'react-dom/client' ;
4
3
5
4
const DEFAULT_OPTIONS = {
6
5
toolbar : 'no' ,
@@ -12,44 +11,47 @@ const DEFAULT_OPTIONS = {
12
11
resizable : 'yes' ,
13
12
width : 500 ,
14
13
height : 400 ,
15
- top : ( o , w ) => ( w . innerHeight - o . height ) / 2 + w . screenY ,
16
- left : ( o , w ) => ( w . innerWidth - o . width ) / 2 + w . screenX
14
+ top : ( o : any , w : any ) => ( w . innerHeight - o . height ) / 2 + w . screenY ,
15
+ left : ( o : any , w : any ) => ( w . innerWidth - o . width ) / 2 + w . screenX ,
17
16
} ;
18
17
19
18
const ABOUT_BLANK = 'about:blank' ;
20
19
20
+ interface PopoutWindowProps extends PropsWithChildren < any > {
21
+ options : object ;
22
+ url : string ;
23
+ containerId : string ;
24
+ containerClassName ?: string ;
25
+ onError : ( ) => void ;
26
+ window ?: Window ;
27
+ title ?: string ;
28
+ }
29
+
30
+ interface PopoutWindowState {
31
+ popoutWindow : Window | null ;
32
+ container : HTMLDivElement | null ;
33
+ openedWindowComponent : React . Component | null ;
34
+ }
35
+
21
36
/**
22
37
* @class PopoutWindow
23
38
*/
24
- export default class PopoutWindow extends React . Component {
39
+ export default class PopoutWindow extends React . Component < PopoutWindowProps , PopoutWindowState > {
40
+ private interval ! : number ;
41
+ private root ! : Root ;
42
+
25
43
static defaultProps = {
26
44
url : ABOUT_BLANK ,
27
45
containerId : 'popout-content-container' ,
28
46
containerClassName : '' ,
29
- onError : ( ) => { }
30
- } ;
31
-
32
- /**
33
- *
34
- * @type {{title: *, url: *, onClosing: *, options: *, window: *, containerId: *} }
35
- */
36
- static propTypes = {
37
- title : PropTypes . string . isRequired ,
38
- url : PropTypes . string ,
39
- onClosing : PropTypes . func ,
40
- options : PropTypes . object ,
41
- window : PropTypes . object ,
42
- containerId : PropTypes . string ,
43
- containerClassName : PropTypes . string ,
44
- children : PropTypes . oneOfType ( [ PropTypes . element , PropTypes . func ] ) ,
45
- onError : PropTypes . func
47
+ onError : ( ) => { } ,
46
48
} ;
47
49
48
50
/**
49
51
* @constructs PopoutWindow
50
52
* @param props
51
53
*/
52
- constructor ( props ) {
54
+ constructor ( props : PopoutWindowProps ) {
53
55
super ( props ) ;
54
56
55
57
this . mainWindowClosed = this . mainWindowClosed . bind ( this ) ;
@@ -59,21 +61,24 @@ export default class PopoutWindow extends React.Component {
59
61
this . state = {
60
62
openedWindowComponent : null ,
61
63
popoutWindow : null ,
62
- container : null
64
+ container : null ,
63
65
} ;
64
66
}
65
67
66
- createOptions ( ownerWindow ) {
68
+ createOptions ( ownerWindow : Window ) {
67
69
const mergedOptions = Object . assign ( { } , DEFAULT_OPTIONS , this . props . options ) ;
68
70
69
71
return Object . keys ( mergedOptions )
70
72
. map (
71
- key =>
73
+ ( key ) =>
72
74
key +
73
75
'=' +
76
+ // @ts -ignore
74
77
( typeof mergedOptions [ key ] === 'function'
75
- ? mergedOptions [ key ] . call ( this , mergedOptions , ownerWindow )
76
- : mergedOptions [ key ] )
78
+ ? // @ts -ignore
79
+ mergedOptions [ key ] . call ( this , mergedOptions , ownerWindow )
80
+ : // @ts -ignore
81
+ mergedOptions [ key ] ) ,
77
82
)
78
83
. join ( ',' ) ;
79
84
}
@@ -90,44 +95,45 @@ export default class PopoutWindow extends React.Component {
90
95
}
91
96
}
92
97
93
- componentWillReceiveProps ( newProps ) {
98
+ componentWillReceiveProps ( newProps : PopoutWindowProps ) {
94
99
if ( newProps . title !== this . props . title && this . state . popoutWindow ) {
95
- this . state . popoutWindow . document . title = newProps . title ;
100
+ this . state . popoutWindow . document . title = newProps . title ! ;
96
101
}
97
102
}
98
103
99
104
componentDidUpdate ( ) {
100
- this . renderToContainer ( this . state . container , this . state . popoutWindow , this . props . children ) ;
105
+ this . renderToContainer ( this . state . container ! , this . state . popoutWindow ! , this . props . children ) ;
101
106
}
102
107
103
108
componentWillUnmount ( ) {
104
109
this . mainWindowClosed ( ) ;
105
110
}
106
111
107
- popoutWindowLoaded ( popoutWindow ) {
112
+ popoutWindowLoaded ( popoutWindow : Window ) {
108
113
if ( ! this . state . container ) {
109
114
// Popout window is passed from openPopoutWindow if no url is specified.
110
115
// In this case this.state.popoutWindow will not yet be set, so use the argument.
111
116
popoutWindow = this . state . popoutWindow || popoutWindow ;
112
- popoutWindow . document . title = this . props . title ;
117
+ popoutWindow . document . title = this . props . title ! ;
113
118
let container = popoutWindow . document . createElement ( 'div' ) ;
114
119
container . id = this . props . containerId ;
115
- container . className = this . props . containerClassName ;
120
+ container . className = this . props . containerClassName ! ;
116
121
popoutWindow . document . body . appendChild ( container ) ;
117
122
118
123
this . setState ( { container } ) ;
119
124
this . renderToContainer ( container , popoutWindow , this . props . children ) ;
120
125
}
121
126
}
122
127
123
- openPopoutWindow ( ownerWindow ) {
128
+ openPopoutWindow ( ownerWindow : Window ) {
124
129
const popoutWindow = ownerWindow . open ( this . props . url , this . props . name || this . props . title , this . createOptions ( ownerWindow ) ) ;
125
130
if ( ! popoutWindow ) {
126
131
this . props . onError ( ) ;
127
132
return ;
128
133
}
129
134
this . setState ( { popoutWindow } ) ;
130
135
136
+ // @ts -ignore
131
137
popoutWindow . addEventListener ( 'load' , this . popoutWindowLoaded ) ;
132
138
popoutWindow . addEventListener ( 'unload' , this . popoutWindowUnloading ) ;
133
139
@@ -153,8 +159,8 @@ export default class PopoutWindow extends React.Component {
153
159
*
154
160
* @param popoutWindow
155
161
*/
156
- checkForPopoutWindowClosure ( popoutWindow ) {
157
- this . interval = setInterval ( ( ) => {
162
+ checkForPopoutWindowClosure ( popoutWindow : Window ) {
163
+ this . interval = window . setInterval ( ( ) => {
158
164
if ( popoutWindow . closed ) {
159
165
clearInterval ( this . interval ) ;
160
166
this . props . onClosing && this . props . onClosing ( popoutWindow ) ;
@@ -170,18 +176,15 @@ export default class PopoutWindow extends React.Component {
170
176
popoutWindowUnloading ( ) {
171
177
if ( this . state . container ) {
172
178
clearInterval ( this . interval ) ;
173
- this . root . unmount ( this . state . container ) ;
179
+ this . root . unmount ( ) ;
174
180
this . props . onClosing && this . props . onClosing ( this . state . popoutWindow ) ;
175
181
}
176
182
}
177
183
178
- renderToContainer ( container , popoutWindow , children ) {
184
+ renderToContainer ( container : HTMLDivElement , popoutWindow : Window , children : React . ReactNode | ( ( window : Window ) => React . ReactNode ) ) {
179
185
// For SSR we might get updated but there will be no container.
180
186
if ( container ) {
181
- let renderedComponent = children ;
182
- if ( typeof children === 'function' ) {
183
- renderedComponent = children ( popoutWindow ) ;
184
- }
187
+ const renderedComponent = typeof children === 'function' ? children ( popoutWindow ) : children ;
185
188
186
189
if ( ! this . root ) {
187
190
this . root = createRoot ( container ) ;
0 commit comments