@@ -210,23 +210,39 @@ export default function useAlign(
210
210
const targetWidth = targetRect . width ;
211
211
212
212
// 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 ;
230
246
231
247
// Reset back
232
248
popupElement . style . left = originLeft ;
@@ -279,17 +295,21 @@ export default function useAlign(
279
295
280
296
// ============== Intersection ===============
281
297
// 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
+ ) {
283
303
const l = popupRect . x + offsetX ;
284
304
const t = popupRect . y + offsetY ;
285
305
286
306
const r = l + popupWidth ;
287
307
const b = t + popupHeight ;
288
308
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 ) ;
293
313
294
314
return Math . max ( 0 , ( visibleR - visibleL ) * ( visibleB - visibleT ) ) ;
295
315
}
@@ -299,6 +319,13 @@ export default function useAlign(
299
319
nextOffsetY ,
300
320
) ;
301
321
322
+ // As `visibleFirst`, we prepare this for check
323
+ const originIntersectionRecommendArea = getIntersectionVisibleArea (
324
+ nextOffsetX ,
325
+ nextOffsetY ,
326
+ visibleRegionArea ,
327
+ ) ;
328
+
302
329
// ========================== Overflow ===========================
303
330
const targetAlignPointTL = getAlignPoint ( targetRect , [ 't' , 'l' ] ) ;
304
331
const popupAlignPointTL = getAlignPoint ( popupRect , [ 't' , 'l' ] ) ;
@@ -338,7 +365,8 @@ export default function useAlign(
338
365
if (
339
366
needAdjustY &&
340
367
popupPoints [ 0 ] === 't' &&
341
- ( nextPopupBottom > visibleArea . bottom || prevFlipRef . current . bt )
368
+ ( nextPopupBottom > adjustCheckVisibleArea . bottom ||
369
+ prevFlipRef . current . bt )
342
370
) {
343
371
let tmpNextOffsetY : number = nextOffsetY ;
344
372
@@ -349,9 +377,23 @@ export default function useAlign(
349
377
targetAlignPointTL . y - popupAlignPointBR . y - popupOffsetY ;
350
378
}
351
379
380
+ const newVisibleArea = getIntersectionVisibleArea (
381
+ nextOffsetX ,
382
+ tmpNextOffsetY ,
383
+ ) ;
384
+ const newVisibleRecommendArea = getIntersectionVisibleArea (
385
+ nextOffsetX ,
386
+ tmpNextOffsetY ,
387
+ visibleRegionArea ,
388
+ ) ;
389
+
352
390
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 ) )
355
397
) {
356
398
prevFlipRef . current . bt = true ;
357
399
nextOffsetY = tmpNextOffsetY ;
@@ -369,7 +411,7 @@ export default function useAlign(
369
411
if (
370
412
needAdjustY &&
371
413
popupPoints [ 0 ] === 'b' &&
372
- ( nextPopupY < visibleArea . top || prevFlipRef . current . tb )
414
+ ( nextPopupY < adjustCheckVisibleArea . top || prevFlipRef . current . tb )
373
415
) {
374
416
let tmpNextOffsetY : number = nextOffsetY ;
375
417
@@ -380,9 +422,23 @@ export default function useAlign(
380
422
targetAlignPointBR . y - popupAlignPointTL . y - popupOffsetY ;
381
423
}
382
424
425
+ const newVisibleArea = getIntersectionVisibleArea (
426
+ nextOffsetX ,
427
+ tmpNextOffsetY ,
428
+ ) ;
429
+ const newVisibleRecommendArea = getIntersectionVisibleArea (
430
+ nextOffsetX ,
431
+ tmpNextOffsetY ,
432
+ visibleRegionArea ,
433
+ ) ;
434
+
383
435
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 ) )
386
442
) {
387
443
prevFlipRef . current . tb = true ;
388
444
nextOffsetY = tmpNextOffsetY ;
@@ -406,7 +462,8 @@ export default function useAlign(
406
462
if (
407
463
needAdjustX &&
408
464
popupPoints [ 1 ] === 'l' &&
409
- ( nextPopupRight > visibleArea . right || prevFlipRef . current . rl )
465
+ ( nextPopupRight > adjustCheckVisibleArea . right ||
466
+ prevFlipRef . current . rl )
410
467
) {
411
468
let tmpNextOffsetX : number = nextOffsetX ;
412
469
@@ -417,9 +474,23 @@ export default function useAlign(
417
474
targetAlignPointTL . x - popupAlignPointBR . x - popupOffsetX ;
418
475
}
419
476
477
+ const newVisibleArea = getIntersectionVisibleArea (
478
+ tmpNextOffsetX ,
479
+ nextOffsetY ,
480
+ ) ;
481
+ const newVisibleRecommendArea = getIntersectionVisibleArea (
482
+ tmpNextOffsetX ,
483
+ nextOffsetY ,
484
+ visibleRegionArea ,
485
+ ) ;
486
+
420
487
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 ) )
423
494
) {
424
495
prevFlipRef . current . rl = true ;
425
496
nextOffsetX = tmpNextOffsetX ;
@@ -437,7 +508,7 @@ export default function useAlign(
437
508
if (
438
509
needAdjustX &&
439
510
popupPoints [ 1 ] === 'r' &&
440
- ( nextPopupX < visibleArea . left || prevFlipRef . current . lr )
511
+ ( nextPopupX < adjustCheckVisibleArea . left || prevFlipRef . current . lr )
441
512
) {
442
513
let tmpNextOffsetX : number = nextOffsetX ;
443
514
@@ -448,9 +519,23 @@ export default function useAlign(
448
519
targetAlignPointBR . x - popupAlignPointTL . x - popupOffsetX ;
449
520
}
450
521
522
+ const newVisibleArea = getIntersectionVisibleArea (
523
+ tmpNextOffsetX ,
524
+ nextOffsetY ,
525
+ ) ;
526
+ const newVisibleRecommendArea = getIntersectionVisibleArea (
527
+ tmpNextOffsetX ,
528
+ nextOffsetY ,
529
+ visibleRegionArea ,
530
+ ) ;
531
+
451
532
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 ) )
454
539
) {
455
540
prevFlipRef . current . lr = true ;
456
541
nextOffsetX = tmpNextOffsetX ;
0 commit comments