@@ -13,36 +13,54 @@ import { Placeholder, Spinner, Disabled } from '@wordpress/components';
13
13
import { __ } from '@wordpress/i18n' ;
14
14
15
15
export default function Preview ( { idBase, instance, isVisible } ) {
16
- const [ iframeHeight , setIframeHeight ] = useState ( ) ;
16
+ const [ isLoaded , setIsLoaded ] = useState ( false ) ;
17
17
18
18
// Resize the iframe on either the load event, or when the iframe becomes visible.
19
- const ref = useRefEffect ( ( iframe ) => {
20
- function onChange ( ) {
21
- const boundingRect = iframe ?. contentDocument ?. body ?. getBoundingClientRect ( ) ;
22
- if ( boundingRect ) {
23
- // Include `top` in the height calculation to avoid the bottom
24
- // of widget previews being cut-off. Most widgets have a
25
- // heading at the top that has top margin, and the `height`
26
- // alone doesn't take that margin into account.
27
- setIframeHeight ( boundingRect . top + boundingRect . height ) ;
28
- }
29
- }
19
+ const ref = useRefEffect (
20
+ ( iframe ) => {
21
+ // Only set height if the iframe is loaded,
22
+ // or it will grow to an unexpected large height in Safari if it's hidden initially.
23
+ if ( isLoaded ) {
24
+ // If the preview frame has another origin then this won't work.
25
+ // One possible solution is to add custom script to call `postMessage` in the preview frame.
26
+ // Or, better yet, we migrate away from iframe.
27
+ function setHeight ( ) {
28
+ // Pick the maximum of these two values to account for margin collapsing.
29
+ const height = Math . max (
30
+ iframe . contentDocument . documentElement . offsetHeight ,
31
+ iframe . contentDocument . body . offsetHeight
32
+ ) ;
33
+ iframe . style . height = `${ height } px` ;
34
+ }
30
35
31
- const { IntersectionObserver } = iframe . ownerDocument . defaultView ;
36
+ const {
37
+ IntersectionObserver,
38
+ } = iframe . ownerDocument . defaultView ;
32
39
33
- // Observe for intersections that might cause a change in the height of
34
- // the iframe, e.g. a Widget Area becoming expanded.
35
- const intersectionObserver = new IntersectionObserver ( onChange , {
36
- threshold : 1 ,
37
- } ) ;
38
- intersectionObserver . observe ( iframe ) ;
40
+ // Observe for intersections that might cause a change in the height of
41
+ // the iframe, e.g. a Widget Area becoming expanded.
42
+ const intersectionObserver = new IntersectionObserver (
43
+ ( [ entry ] ) => {
44
+ if ( entry . isIntersecting ) {
45
+ setHeight ( ) ;
46
+ }
47
+ } ,
48
+ {
49
+ threshold : 1 ,
50
+ }
51
+ ) ;
52
+ intersectionObserver . observe ( iframe ) ;
39
53
40
- iframe . addEventListener ( 'load' , onChange ) ;
54
+ iframe . addEventListener ( 'load' , setHeight ) ;
41
55
42
- return ( ) => {
43
- iframe . removeEventListener ( 'load' , onChange ) ;
44
- } ;
45
- } , [ ] ) ;
56
+ return ( ) => {
57
+ intersectionObserver . disconnect ( ) ;
58
+ iframe . removeEventListener ( 'load' , setHeight ) ;
59
+ } ;
60
+ }
61
+ } ,
62
+ [ isLoaded ]
63
+ ) ;
46
64
47
65
return (
48
66
< >
@@ -53,7 +71,7 @@ export default function Preview( { idBase, instance, isVisible } ) {
53
71
move the iframe off-screen instead of hiding it because web browsers
54
72
will not trigger onLoad if the iframe is hidden.
55
73
*/ }
56
- { isVisible && iframeHeight === null && (
74
+ { isVisible && ! isLoaded && (
57
75
< Placeholder >
58
76
< Spinner />
59
77
</ Placeholder >
@@ -62,7 +80,7 @@ export default function Preview( { idBase, instance, isVisible } ) {
62
80
className = { classnames (
63
81
'wp-block-legacy-widget__edit-preview' ,
64
82
{
65
- 'is-offscreen' : ! isVisible || iframeHeight === null ,
83
+ 'is-offscreen' : ! isVisible || ! isLoaded ,
66
84
}
67
85
) }
68
86
>
@@ -84,7 +102,17 @@ export default function Preview( { idBase, instance, isVisible } ) {
84
102
instance,
85
103
} ,
86
104
} ) }
87
- height = { iframeHeight || 100 }
105
+ onLoad = { ( event ) => {
106
+ // To hide the scrollbars of the preview frame for some edge cases,
107
+ // such as negative margins in the Gallery Legacy Widget.
108
+ // It can't be scrolled anyway.
109
+ // TODO: Ideally, this should be fixed in core.
110
+ event . target . contentDocument . body . style . overflow =
111
+ 'hidden' ;
112
+
113
+ setIsLoaded ( true ) ;
114
+ } }
115
+ height = { 100 }
88
116
/>
89
117
</ Disabled >
90
118
</ div >
0 commit comments