@@ -10,12 +10,12 @@ const BACKDROP_CLICK_MAX_MOVEMENT = 4
1010/** Edge margin when fitting to the device screen (not the inner panel only). */
1111const SCREEN_FIT_PADDING_PX = 12
1212
13- function getScreenFitSize ( ) : { width : number ; height : number } {
13+ export function getScreenFitSize ( reservedTopPx = 0 ) : { width : number ; height : number } {
1414 const viewport = window . visualViewport
15- if ( viewport ) {
16- return { width : viewport . width , height : viewport . height }
17- }
18- return { width : window . innerWidth , height : window . innerHeight }
15+ const width = viewport ? viewport . width : window . innerWidth
16+ const fullHeight = viewport ? viewport . height : window . innerHeight
17+ const reserved = Math . max ( 0 , reservedTopPx )
18+ return { width, height : Math . max ( 0 , fullHeight - reserved ) }
1919}
2020
2121type Point = { x : number ; y : number }
@@ -128,11 +128,13 @@ export function ZoomableLightbox(props: ZoomableLightboxProps) {
128128 } = props
129129 const [ scale , setScale ] = useState ( 1 )
130130 const [ offset , setOffset ] = useState ( { x : 0 , y : 0 } )
131+ const [ toolbarHeight , setToolbarHeight ] = useState ( 0 )
131132 const scaleRef = useRef ( scale )
132133 const offsetRef = useRef ( offset )
133134 const baseScaleRef = useRef ( 1 )
134135 const viewportRef = useRef < HTMLDivElement > ( null )
135136 const contentRef = useRef < HTMLDivElement > ( null )
137+ const toolbarRef = useRef < HTMLDivElement > ( null )
136138 const activePointersRef = useRef ( new Map < number , Point > ( ) )
137139 const dragRef = useRef < { pointerId : number ; startX : number ; startY : number ; originX : number ; originY : number } | null > ( null )
138140 const pinchRef = useRef < { startDistance : number ; startScale : number ; startCenter : Point ; origin : Point } | null > ( null )
@@ -165,7 +167,7 @@ export function ZoomableLightbox(props: ZoomableLightboxProps) {
165167 const contentSize = fitContentSize ?? measureContentSize ( content , scaleRef . current )
166168 if ( ! contentSize ) return
167169
168- const screen = getScreenFitSize ( )
170+ const screen = getScreenFitSize ( toolbarHeight )
169171 const pad = SCREEN_FIT_PADDING_PX * 2
170172 const fitWidth = ( screen . width - pad ) / contentSize . width
171173 const fitHeight = ( screen . height - pad ) / contentSize . height
@@ -174,7 +176,7 @@ export function ZoomableLightbox(props: ZoomableLightboxProps) {
174176 baseScaleRef . current = fitScale
175177 updateScale ( fitScale )
176178 updateOffset ( { x : 0 , y : 0 } )
177- } , [ fitContentSize , fitOnOpen , updateOffset , updateScale ] )
179+ } , [ fitContentSize , fitOnOpen , toolbarHeight , updateOffset , updateScale ] )
178180
179181 const resetView = useCallback ( ( ) => {
180182 updateScale ( baseScaleRef . current )
@@ -346,6 +348,26 @@ export function ZoomableLightbox(props: ZoomableLightboxProps) {
346348 }
347349 } , [ fitContentKey , fitContentSize , fitOnOpen , open , applyFitScale ] )
348350
351+ useLayoutEffect ( ( ) => {
352+ if ( ! open ) return undefined
353+ const toolbar = toolbarRef . current
354+ if ( ! toolbar ) return undefined
355+
356+ const apply = ( ) => {
357+ const next = toolbar . getBoundingClientRect ( ) . height
358+ setToolbarHeight ( ( current ) => ( Math . abs ( current - next ) < 0.5 ? current : next ) )
359+ }
360+
361+ apply ( )
362+ const resize = new ResizeObserver ( apply )
363+ resize . observe ( toolbar )
364+ window . addEventListener ( 'resize' , apply )
365+ return ( ) => {
366+ resize . disconnect ( )
367+ window . removeEventListener ( 'resize' , apply )
368+ }
369+ } , [ open ] )
370+
349371 useEffect ( ( ) => {
350372 if ( ! open ) return
351373
@@ -385,7 +407,8 @@ export function ZoomableLightbox(props: ZoomableLightboxProps) {
385407 >
386408 < div
387409 ref = { viewportRef }
388- className = "absolute inset-0 cursor-grab touch-none overflow-hidden active:cursor-grabbing"
410+ className = "absolute inset-x-0 bottom-0 cursor-grab touch-none overflow-hidden active:cursor-grabbing"
411+ style = { { top : `${ toolbarHeight } px` } }
389412 onWheel = { handleWheel }
390413 onPointerDown = { handlePointerDown }
391414 onPointerMove = { handlePointerMove }
@@ -405,6 +428,7 @@ export function ZoomableLightbox(props: ZoomableLightboxProps) {
405428 </ div >
406429 </ div >
407430 < div
431+ ref = { toolbarRef }
408432 className = "pointer-events-none absolute inset-x-0 top-0 z-10 pt-[env(safe-area-inset-top,0px)]"
409433 onPointerDown = { ( event ) => event . stopPropagation ( ) }
410434 >
0 commit comments