@@ -210,23 +210,39 @@ export default function useAlign(
210210 const targetWidth = targetRect . width ;
211211
212212 // Get bounding of visible area
213- let visibleArea =
214- placementInfo . htmlRegion === 'scroll'
215- ? // Scroll region should take scrollLeft & scrollTop into account
216- {
217- left : - scrollLeft ,
218- top : - scrollTop ,
219- right : scrollWidth - scrollLeft ,
220- bottom : scrollHeight - scrollTop ,
221- }
222- : {
223- left : 0 ,
224- top : 0 ,
225- right : clientWidth ,
226- bottom : clientHeight ,
227- } ;
228-
229- visibleArea = getVisibleArea ( visibleArea , scrollerList ) ;
213+ const visibleRegion = {
214+ left : 0 ,
215+ top : 0 ,
216+ right : clientWidth ,
217+ bottom : clientHeight ,
218+ } ;
219+
220+ const scrollRegion = {
221+ left : - scrollLeft ,
222+ top : - scrollTop ,
223+ right : scrollWidth - scrollLeft ,
224+ bottom : scrollHeight - scrollTop ,
225+ } ;
226+
227+ let { htmlRegion } = placementInfo ;
228+ const VISIBLE = 'visible' as const ;
229+ const VISIBLE_FIRST = 'visibleFirst' as const ;
230+ if ( htmlRegion !== 'scroll' && htmlRegion !== VISIBLE_FIRST ) {
231+ htmlRegion = VISIBLE ;
232+ }
233+ const isVisibleFirst = htmlRegion === VISIBLE_FIRST ;
234+
235+ const scrollRegionArea = getVisibleArea ( scrollRegion , scrollerList ) ;
236+ const visibleRegionArea = getVisibleArea ( visibleRegion , scrollerList ) ;
237+
238+ const visibleArea =
239+ htmlRegion === VISIBLE ? visibleRegionArea : scrollRegionArea ;
240+
241+ // When set to `visibleFirst`,
242+ // the check `adjust` logic will use `visibleRegion` for check first.
243+ const adjustCheckVisibleArea = isVisibleFirst
244+ ? visibleRegionArea
245+ : visibleArea ;
230246
231247 // Reset back
232248 popupElement . style . left = originLeft ;
@@ -279,17 +295,21 @@ export default function useAlign(
279295
280296 // ============== Intersection ===============
281297 // Get area by position. Used for check if flip area is better
282- function getIntersectionVisibleArea ( offsetX : number , offsetY : number ) {
298+ function getIntersectionVisibleArea (
299+ offsetX : number ,
300+ offsetY : number ,
301+ area = visibleArea ,
302+ ) {
283303 const l = popupRect . x + offsetX ;
284304 const t = popupRect . y + offsetY ;
285305
286306 const r = l + popupWidth ;
287307 const b = t + popupHeight ;
288308
289- const visibleL = Math . max ( l , visibleArea . left ) ;
290- const visibleT = Math . max ( t , visibleArea . top ) ;
291- const visibleR = Math . min ( r , visibleArea . right ) ;
292- const visibleB = Math . min ( b , visibleArea . bottom ) ;
309+ const visibleL = Math . max ( l , area . left ) ;
310+ const visibleT = Math . max ( t , area . top ) ;
311+ const visibleR = Math . min ( r , area . right ) ;
312+ const visibleB = Math . min ( b , area . bottom ) ;
293313
294314 return Math . max ( 0 , ( visibleR - visibleL ) * ( visibleB - visibleT ) ) ;
295315 }
@@ -299,6 +319,13 @@ export default function useAlign(
299319 nextOffsetY ,
300320 ) ;
301321
322+ // As `visibleFirst`, we prepare this for check
323+ const originIntersectionRecommendArea = getIntersectionVisibleArea (
324+ nextOffsetX ,
325+ nextOffsetY ,
326+ visibleRegionArea ,
327+ ) ;
328+
302329 // ========================== Overflow ===========================
303330 const targetAlignPointTL = getAlignPoint ( targetRect , [ 't' , 'l' ] ) ;
304331 const popupAlignPointTL = getAlignPoint ( popupRect , [ 't' , 'l' ] ) ;
@@ -338,7 +365,8 @@ export default function useAlign(
338365 if (
339366 needAdjustY &&
340367 popupPoints [ 0 ] === 't' &&
341- ( nextPopupBottom > visibleArea . bottom || prevFlipRef . current . bt )
368+ ( nextPopupBottom > adjustCheckVisibleArea . bottom ||
369+ prevFlipRef . current . bt )
342370 ) {
343371 let tmpNextOffsetY : number = nextOffsetY ;
344372
@@ -349,9 +377,23 @@ export default function useAlign(
349377 targetAlignPointTL . y - popupAlignPointBR . y - popupOffsetY ;
350378 }
351379
380+ const newVisibleArea = getIntersectionVisibleArea (
381+ nextOffsetX ,
382+ tmpNextOffsetY ,
383+ ) ;
384+ const newVisibleRecommendArea = getIntersectionVisibleArea (
385+ nextOffsetX ,
386+ tmpNextOffsetY ,
387+ visibleRegionArea ,
388+ ) ;
389+
352390 if (
353- getIntersectionVisibleArea ( nextOffsetX , tmpNextOffsetY ) >=
354- originIntersectionVisibleArea
391+ // Of course use larger one
392+ newVisibleArea > originIntersectionVisibleArea ||
393+ ( newVisibleArea === originIntersectionVisibleArea &&
394+ ( ! isVisibleFirst ||
395+ // Choose recommend one
396+ newVisibleRecommendArea >= originIntersectionRecommendArea ) )
355397 ) {
356398 prevFlipRef . current . bt = true ;
357399 nextOffsetY = tmpNextOffsetY ;
@@ -369,7 +411,7 @@ export default function useAlign(
369411 if (
370412 needAdjustY &&
371413 popupPoints [ 0 ] === 'b' &&
372- ( nextPopupY < visibleArea . top || prevFlipRef . current . tb )
414+ ( nextPopupY < adjustCheckVisibleArea . top || prevFlipRef . current . tb )
373415 ) {
374416 let tmpNextOffsetY : number = nextOffsetY ;
375417
@@ -380,9 +422,23 @@ export default function useAlign(
380422 targetAlignPointBR . y - popupAlignPointTL . y - popupOffsetY ;
381423 }
382424
425+ const newVisibleArea = getIntersectionVisibleArea (
426+ nextOffsetX ,
427+ tmpNextOffsetY ,
428+ ) ;
429+ const newVisibleRecommendArea = getIntersectionVisibleArea (
430+ nextOffsetX ,
431+ tmpNextOffsetY ,
432+ visibleRegionArea ,
433+ ) ;
434+
383435 if (
384- getIntersectionVisibleArea ( nextOffsetX , tmpNextOffsetY ) >=
385- originIntersectionVisibleArea
436+ // Of course use larger one
437+ newVisibleArea > originIntersectionVisibleArea ||
438+ ( newVisibleArea === originIntersectionVisibleArea &&
439+ ( ! isVisibleFirst ||
440+ // Choose recommend one
441+ newVisibleRecommendArea >= originIntersectionRecommendArea ) )
386442 ) {
387443 prevFlipRef . current . tb = true ;
388444 nextOffsetY = tmpNextOffsetY ;
@@ -406,7 +462,8 @@ export default function useAlign(
406462 if (
407463 needAdjustX &&
408464 popupPoints [ 1 ] === 'l' &&
409- ( nextPopupRight > visibleArea . right || prevFlipRef . current . rl )
465+ ( nextPopupRight > adjustCheckVisibleArea . right ||
466+ prevFlipRef . current . rl )
410467 ) {
411468 let tmpNextOffsetX : number = nextOffsetX ;
412469
@@ -417,9 +474,23 @@ export default function useAlign(
417474 targetAlignPointTL . x - popupAlignPointBR . x - popupOffsetX ;
418475 }
419476
477+ const newVisibleArea = getIntersectionVisibleArea (
478+ tmpNextOffsetX ,
479+ nextOffsetY ,
480+ ) ;
481+ const newVisibleRecommendArea = getIntersectionVisibleArea (
482+ tmpNextOffsetX ,
483+ nextOffsetY ,
484+ visibleRegionArea ,
485+ ) ;
486+
420487 if (
421- getIntersectionVisibleArea ( tmpNextOffsetX , nextOffsetY ) >=
422- originIntersectionVisibleArea
488+ // Of course use larger one
489+ newVisibleArea > originIntersectionVisibleArea ||
490+ ( newVisibleArea === originIntersectionVisibleArea &&
491+ ( ! isVisibleFirst ||
492+ // Choose recommend one
493+ newVisibleRecommendArea >= originIntersectionRecommendArea ) )
423494 ) {
424495 prevFlipRef . current . rl = true ;
425496 nextOffsetX = tmpNextOffsetX ;
@@ -437,7 +508,7 @@ export default function useAlign(
437508 if (
438509 needAdjustX &&
439510 popupPoints [ 1 ] === 'r' &&
440- ( nextPopupX < visibleArea . left || prevFlipRef . current . lr )
511+ ( nextPopupX < adjustCheckVisibleArea . left || prevFlipRef . current . lr )
441512 ) {
442513 let tmpNextOffsetX : number = nextOffsetX ;
443514
@@ -448,9 +519,23 @@ export default function useAlign(
448519 targetAlignPointBR . x - popupAlignPointTL . x - popupOffsetX ;
449520 }
450521
522+ const newVisibleArea = getIntersectionVisibleArea (
523+ tmpNextOffsetX ,
524+ nextOffsetY ,
525+ ) ;
526+ const newVisibleRecommendArea = getIntersectionVisibleArea (
527+ tmpNextOffsetX ,
528+ nextOffsetY ,
529+ visibleRegionArea ,
530+ ) ;
531+
451532 if (
452- getIntersectionVisibleArea ( tmpNextOffsetX , nextOffsetY ) >=
453- originIntersectionVisibleArea
533+ // Of course use larger one
534+ newVisibleArea > originIntersectionVisibleArea ||
535+ ( newVisibleArea === originIntersectionVisibleArea &&
536+ ( ! isVisibleFirst ||
537+ // Choose recommend one
538+ newVisibleRecommendArea >= originIntersectionRecommendArea ) )
454539 ) {
455540 prevFlipRef . current . lr = true ;
456541 nextOffsetX = tmpNextOffsetX ;
0 commit comments