Skip to content

Commit 51e501e

Browse files
authored
fix (design library): design preview scale adjustment (#3598)
* fix scale adjustment * minor fix * fix designs not displaying correctly * fix coderabbit's qa * use double rAF * store rAF * increase root margin
1 parent 86023f7 commit 51e501e

File tree

6 files changed

+133
-92
lines changed

6 files changed

+133
-92
lines changed

src/components/design-library-list/design-library-list-item.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,22 @@ const DesignLibraryListItem = forwardRef( ( props, ref ) => {
4646
const {
4747
blocks, enableBackground,
4848
shadowBodySizeRef, blocksForSubstitutionRef,
49-
adjustScale, onClickDesign,
49+
onClickDesign,
5050
} = usePreviewRenderer(
5151
previewProps, previewSize, plan, spacingSize,
5252
selectedTab, selectedNum, selectedData,
53-
ref, shadowRoot, setIsLoading
53+
ref, hostRef, shadowRoot, setIsLoading,
5454
)
5555

5656
const {
5757
onMouseOut, onMouseOver, onMouseDown,
5858
} = useAutoScroll( hostRef, shadowBodySizeRef, selectedTab )
5959

6060
const getDesignPreviewSize = () => {
61+
if ( ! shadowRoot || isLoading ) {
62+
return 0
63+
}
64+
6165
return selectedNum && selectedData ? selectedData.selectedPreviewSize.preview
6266
: ( enableBackground ? previewSize.heightBackground : previewSize.heightNoBackground )
6367
}
@@ -88,7 +92,7 @@ const DesignLibraryListItem = forwardRef( ( props, ref ) => {
8892
onMouseOver={ onMouseOver }
8993
>
9094
{ ! isPro && plan !== 'free' && <span className="stk-pulsating-circle" role="presentation" /> }
91-
<div style={ { position: 'relative' } } className={ `${ getDesignPreviewSize() > 100 ? 'stk--design-preview-large' : 'stk--design-preview-small' }` }>
95+
<div style={ { position: 'relative' } } className={ `stk-block-design__design-container ${ getDesignPreviewSize() > 100 ? 'stk--design-preview-large' : 'stk--design-preview-small' }` }>
9296
{ ! isPro && plan !== 'free' && (
9397
<ProControl
9498
type="design-library"
@@ -106,11 +110,10 @@ const DesignLibraryListItem = forwardRef( ( props, ref ) => {
106110
} }
107111
>
108112
<div className="stk-block-design__host" ref={ hostRef }>
109-
{ shadowRoot && <DesignPreview
113+
{ shadowRoot && ! isLoading && <DesignPreview
110114
blocks={ blocks }
111115
shadowRoot={ shadowRoot }
112116
selectedTab={ selectedTab }
113-
adjustScale={ adjustScale }
114117
onMouseDown={ onMouseDown }
115118
/> }
116119
</div>

src/components/design-library-list/design-preview.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ export const DesignPreview = ( {
1313
blocks = '',
1414
shadowRoot,
1515
selectedTab,
16-
adjustScale = NOOP,
1716
onMouseDown = NOOP,
1817
} ) => {
1918
const ref = useRef( null )
@@ -72,11 +71,6 @@ export const DesignPreview = ( {
7271
}
7372
}, [ selectedTab ] )
7473

75-
useEffect( () => {
76-
// The scale might not be correct on first load, so adjust it again to be sure.
77-
setTimeout( adjustScale, 100 )
78-
}, [] )
79-
8074
const shadowBodyClasses = classnames( applyFilters( 'stackable.global-styles.classnames', [
8175
'entry-content',
8276
] ), {

src/components/design-library-list/editor.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
background: #f4f4f5;
2828
}
2929
.ugb-design-library-item {
30+
width: 100%;
3031
display: grid;
3132
grid-template-columns: 1fr;
3233
padding: 0;

src/components/design-library-list/index.js

Lines changed: 34 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ const DesignLibraryList = props => {
2929
} = props
3030
const containerRef = useRef( null )
3131

32-
const [ scrollTop, setScrollTop ] = useState( 0 )
33-
3432
const listClasses = classnames( [
3533
'ugb-design-library-items',
3634
className,
@@ -43,9 +41,6 @@ const DesignLibraryList = props => {
4341
return <div
4442
className="ugb-modal-design-library__designs"
4543
ref={ containerRef }
46-
onScroll={ e => {
47-
setScrollTop( e.currentTarget.scrollTop )
48-
} }
4944
>
5045
{ isBusy && <Spinner style={ { display: 'block', margin: '0 auto' } } /> }
5146
{ ! isBusy && <>
@@ -73,7 +68,6 @@ const DesignLibraryList = props => {
7368
selectedNum={ selectedNum }
7469
selectedData={ selectedData }
7570
selectedTab={ props.selectedTab }
76-
scrollTop={ scrollTop }
7771
designKey={ i }
7872
/>
7973
)
@@ -98,9 +92,10 @@ export default DesignLibraryList
9892

9993
const DesignLibraryItem = props => {
10094
const {
101-
scrollTop, previewProps: _previewProps, ...propsToPass
95+
previewProps: _previewProps, ...propsToPass
10296
} = props
10397

98+
const wrapperRef = useRef( null )
10499
const itemRef = useRef( null )
105100
const [ cardHeight, setCardHeight ] = useState( {} )
106101
const [ previewSize, setPreviewSize ] = useState( {} )
@@ -114,43 +109,43 @@ const DesignLibraryItem = props => {
114109
}
115110

116111
useEffect( () => {
117-
// Use a timeout to ensure designs have finished rendering before calculating visibility.
118-
const timeoutRef = setTimeout( () => {
119-
const itemEl = itemRef.current
120-
const containerEl = itemEl?.closest( '.ugb-modal-design-library__designs' ) || document.querySelector( '.ugb-modal-design-library__designs' )
121-
122-
if ( ! itemEl || ! containerEl ) {
123-
return
124-
}
125-
126-
const containerRect = containerEl.getBoundingClientRect()
127-
const itemRect = itemEl.getBoundingClientRect()
128-
129-
const BOUNDARY = 250
130-
131-
const render = itemRect.bottom >= containerRect.top - BOUNDARY && itemRect.top <= containerRect.bottom + BOUNDARY
132-
133-
setShouldRender( render )
134-
}, 250 )
135-
136-
return () => {
137-
clearTimeout( timeoutRef )
112+
const rootEl = document.querySelector( '.ugb-modal-design-library__designs' )
113+
if ( ! wrapperRef.current || ! rootEl ) {
114+
return
138115
}
139-
}, [ scrollTop, _previewProps.enableBackground, _previewProps.designId ] )
116+
117+
const observer = new IntersectionObserver( ( [ entry ] ) => {
118+
// reduce flicker during rapid scrolls
119+
requestAnimationFrame( () => {
120+
requestAnimationFrame( () => setShouldRender( entry.isIntersecting ) )
121+
} )
122+
}, {
123+
root: rootEl,
124+
rootMargin: '500px',
125+
threshold: 0,
126+
} )
127+
128+
observer.observe( wrapperRef.current )
129+
return () => observer.disconnect()
130+
}, [] )
140131

141132
const getCardHeight = () => {
142133
const key = _previewProps.enableBackground ? 'background' : 'noBackground'
143134
return props.selectedTab === 'pages' ? 472 : cardHeight?.[ key ] || 250
144135
}
145136

146-
if ( ! shouldRender && ! props.selectedNum ) {
147-
return <div ref={ itemRef } style={ { height: `${ getCardHeight() }px` } } />
148-
}
149-
150-
return <DesignLibraryListItem
151-
ref={ itemRef }
152-
previewSize={ previewSize }
153-
previewProps={ previewProps }
154-
{ ...propsToPass }
155-
/>
137+
return (
138+
<div ref={ wrapperRef }>
139+
{ ! shouldRender && ! props.selectedNum ? (
140+
<div ref={ itemRef } style={ { height: `${ getCardHeight() }px` } } />
141+
) : (
142+
<DesignLibraryListItem
143+
ref={ itemRef }
144+
previewSize={ previewSize }
145+
previewProps={ previewProps }
146+
{ ...propsToPass }
147+
/>
148+
) }
149+
</div>
150+
)
156151
}

src/components/design-library-list/use-preview-renderer.js

Lines changed: 87 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const DEFAULT_CONTENT = { ...DEFAULT }
3737
export const usePreviewRenderer = (
3838
props, previewSize, plan, spacingSize,
3939
selectedTab, selectedNum, selectedData,
40-
ref, shadowRoot, setIsLoading
40+
ref, hostRef, shadowRoot, setIsLoading
4141
) => {
4242
const {
4343
designId,
@@ -61,64 +61,89 @@ export const usePreviewRenderer = (
6161
const hasBackgroundTargetRef = useRef( false )
6262
const initialRenderRef = useRef( null )
6363
const shadowBodySizeRef = useRef( null )
64-
const prevEnableBackgroundRef = useRef( false )
64+
const prevEnableBackgroundRef = useRef( null )
6565
const prevSelectedTabRef = useRef( selectedTab )
66+
const adjustAnimateFrameRef = useRef( null )
6667

6768
const siteTitle = useSelect( select => select( 'core' ).getEntityRecord( 'root', 'site' )?.title || 'InnovateCo', [] )
6869
const isDesignLibraryDevMode = devMode && localStorage.getItem( 'stk__design_library__dev_mode' ) === '1'
6970

7071
const addHasBackground = selectedTab === 'patterns'
7172

72-
const adjustScale = () => {
73-
const shouldAdjust = ref.current && shadowRoot &&
73+
const adjustScale = ( force = true ) => {
74+
const parentDiv = ref?.current?.querySelector( '.stk-block-design__design-container' )
75+
const shouldAdjust = ref.current && hostRef.current && shadowRoot && parentDiv &&
7476
( ! selectedNum || // adjust if design is not selected
7577
prevSelectedTabRef.current !== selectedTab ) // adjust if selected tab changed even if design is selected
7678

77-
if ( shouldAdjust ) {
78-
const newPreviewSize = { ...previewSize }
79-
const newCardHeight = { ...cardHeight }
80-
const cardRect = ref.current.getBoundingClientRect()
79+
if ( ! shouldAdjust ) {
80+
return
81+
}
82+
const newPreviewSize = { ...previewSize }
83+
const newCardHeight = { ...cardHeight }
8184

82-
const shadowBody = shadowRoot.querySelector( 'body' )
83-
if ( shadowBody ) {
84-
const cardWidth = cardRect.width // Get width of the card
85-
const scaleFactor = cardWidth > 0 ? cardWidth / 1300 : 1 // Divide by 1300, which is the width of preview in the shadow DOM
86-
newPreviewSize.scale = scaleFactor
85+
const cardRect = ref.current.getBoundingClientRect()
86+
const hostRect = hostRef.current.getBoundingClientRect()
87+
const parentDivRect = parentDiv.getBoundingClientRect()
8788

88-
let _bodyHeight = 1200
89-
if ( selectedTab === 'patterns' ) {
90-
_bodyHeight = shadowBody.offsetHeight
91-
}
89+
const cardWidth = cardRect.width
90+
const hostWidth = hostRect.width
9291

93-
const _height = parseFloat( _bodyHeight ) * scaleFactor // Also adjust the height
92+
// Consider heights equal if the difference is less than 1px
93+
const isEqualHeight = Math.abs( parentDivRect.height - hostRect.height ) < 1
9494

95-
if ( Object.keys( newPreviewSize ).length === 1 ) {
96-
newPreviewSize.heightBackground = _height
97-
newPreviewSize.heightNoBackground = _height
98-
} else {
99-
const heightKey = enableBackground ? 'heightBackground' : 'heightNoBackground'
100-
newPreviewSize[ heightKey ] = _height
101-
}
95+
if ( ! force && cardWidth === hostWidth && isEqualHeight ) {
96+
if ( adjustAnimateFrameRef.current !== null ) {
97+
cancelAnimationFrame( adjustAnimateFrameRef.current )
98+
}
99+
adjustAnimateFrameRef.current = null
100+
return
101+
}
102102

103-
setPreviewSize( newPreviewSize )
103+
const shadowBody = shadowRoot.querySelector( 'body' )
104+
if ( shadowBody ) {
105+
const cardWidth = cardRect.width // Get width of the card
106+
const scaleFactor = cardWidth > 0 ? cardWidth / 1300 : 1 // Divide by 1300, which is the width of preview in the shadow DOM
107+
newPreviewSize.scale = scaleFactor
104108

105-
shadowBodySizeRef.current = {
106-
clientHeight: shadowBody.clientHeight,
107-
scrollHeight: shadowBody.scrollHeight,
108-
maxScrollTop: shadowBody.scrollHeight - shadowBody.clientHeight,
109-
}
109+
let _bodyHeight = 1200
110+
if ( selectedTab === 'patterns' ) {
111+
_bodyHeight = shadowBody.offsetHeight
110112
}
111113

112-
if ( ! Object.keys( newCardHeight ).length ) {
113-
newCardHeight.background = cardRect.height
114-
newCardHeight.noBackground = cardRect.height
114+
const _height = parseFloat( _bodyHeight ) * scaleFactor // Also adjust the height
115+
116+
if ( Object.keys( newPreviewSize ).length === 1 ) {
117+
newPreviewSize.heightBackground = _height
118+
newPreviewSize.heightNoBackground = _height
115119
} else {
116-
const CardHeightKey = enableBackground ? 'background' : 'noBackground'
117-
newCardHeight[ CardHeightKey ] = cardRect.height
120+
const heightKey = enableBackground ? 'heightBackground' : 'heightNoBackground'
121+
newPreviewSize[ heightKey ] = _height
122+
}
123+
124+
setPreviewSize( newPreviewSize )
125+
126+
shadowBodySizeRef.current = {
127+
clientHeight: shadowBody.clientHeight,
128+
scrollHeight: shadowBody.scrollHeight,
129+
maxScrollTop: shadowBody.scrollHeight - shadowBody.clientHeight,
118130
}
131+
}
132+
133+
if ( ! Object.keys( newCardHeight ).length ) {
134+
newCardHeight.background = cardRect.height
135+
newCardHeight.noBackground = cardRect.height
136+
} else {
137+
const CardHeightKey = enableBackground ? 'background' : 'noBackground'
138+
newCardHeight[ CardHeightKey ] = cardRect.height
139+
}
140+
141+
setTimeout( () => setCardHeight( newCardHeight ), 500 )
119142

120-
setTimeout( () => setCardHeight( newCardHeight ), 500 )
143+
if ( adjustAnimateFrameRef.current !== null ) {
144+
cancelAnimationFrame( adjustAnimateFrameRef.current )
121145
}
146+
adjustAnimateFrameRef.current = requestAnimationFrame( () => adjustScale( false ) )
122147
}
123148

124149
const renderPreview = ( blockContent = content ) => {
@@ -274,7 +299,10 @@ export const usePreviewRenderer = (
274299
useEffect( () => {
275300
if ( selectedNum === 0 && content && shadowRoot ) {
276301
renderPreview()
277-
setTimeout( adjustScale, 100 )
302+
if ( adjustAnimateFrameRef.current !== null ) {
303+
cancelAnimationFrame( adjustAnimateFrameRef.current )
304+
}
305+
adjustAnimateFrameRef.current = requestAnimationFrame( adjustScale )
278306
}
279307
}, [ selectedNum ] )
280308

@@ -285,7 +313,11 @@ export const usePreviewRenderer = (
285313

286314
if ( prevEnableBackgroundRef.current !== enableBackground ) {
287315
prevEnableBackgroundRef.current = enableBackground
288-
adjustScale()
316+
317+
if ( adjustAnimateFrameRef.current !== null ) {
318+
cancelAnimationFrame( adjustAnimateFrameRef.current )
319+
}
320+
adjustAnimateFrameRef.current = requestAnimationFrame( adjustScale )
289321
}
290322
}, [ blocks ] )
291323

@@ -294,12 +326,25 @@ export const usePreviewRenderer = (
294326
if ( ! content || ! blocks.parsed || ! blocks.serialized ) {
295327
return
296328
}
297-
setTimeout( () => {
329+
330+
if ( adjustAnimateFrameRef.current !== null ) {
331+
cancelAnimationFrame( adjustAnimateFrameRef.current )
332+
}
333+
334+
adjustAnimateFrameRef.current = requestAnimationFrame( () => {
298335
adjustScale()
299336
prevSelectedTabRef.current = selectedTab
300-
}, 100 )
337+
} )
301338
}, [ content ] )
302339

340+
// cleanup any pending animation on unmount
341+
useEffect( () => {
342+
return () => {
343+
cancelAnimationFrame( adjustAnimateFrameRef.current )
344+
adjustAnimateFrameRef.current = null
345+
}
346+
}, [] )
347+
303348
const onClickDesign = () => {
304349
if ( ! isPro && plan !== 'free' ) {
305350
return
@@ -319,6 +364,6 @@ export const usePreviewRenderer = (
319364
return {
320365
blocks: blocks.serialized, enableBackground,
321366
shadowBodySizeRef, blocksForSubstitutionRef,
322-
adjustScale, onClickDesign,
367+
onClickDesign,
323368
}
324369
}

src/components/modal-design-library/editor.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@
4545

4646
&.ugb-modal-design-library__full-pages {
4747
grid-template-rows: auto auto;
48+
.ugb-modal-design-library__designs {
49+
grid-row: 1 / -1;
50+
}
4851
}
4952
}
5053
.ugb-modal-design-library__sidebar {

0 commit comments

Comments
 (0)