@@ -23,15 +23,14 @@ import { JSSTheme } from '../../interfaces/JSSTheme';
23
23
import { ObjectPageMode } from '@ui5/webcomponents-react/lib/ObjectPageMode' ;
24
24
import styles from './ObjectPage.jss' ;
25
25
import { ObjectPageAnchorButton } from './ObjectPageAnchorButton' ;
26
- import { Button } from '../../webComponents /Button' ;
26
+ import { Button } from '@ui5/webcomponents-react/lib /Button' ;
27
27
import { CollapsedAvatar } from './CollapsedAvatar' ;
28
28
import { ObjectPageScroller } from './scroll/ObjectPageScroller' ;
29
- import { Avatar } from '@ui5/webcomponents-react/lib/Avatar' ;
30
29
import { AvatarSize } from '@ui5/webcomponents-react/lib/AvatarSize' ;
31
- import { AvatarShape } from '@ui5/webcomponents-react/lib/AvatarShape' ;
32
30
import { ContentDensity } from '@ui5/webcomponents-react/lib/ContentDensity' ;
33
31
import '@ui5/webcomponents/dist/icons/navigation-up-arrow.js' ;
34
32
import { getScrollBarWidth } from '@ui5/webcomponents-react-base/lib/Utils' ;
33
+ import '@ui5/webcomponents/dist/icons/navigation-down-arrow.js' ;
35
34
36
35
export interface ObjectPagePropTypes extends CommonProps {
37
36
title ?: string ;
@@ -101,9 +100,10 @@ const ObjectPage: FC<ObjectPagePropTypes> = forwardRef((props: ObjectPagePropTyp
101
100
const innerScrollBar : RefObject < HTMLDivElement > = useRef ( ) ;
102
101
const contentScrollContainer : RefObject < HTMLDivElement > = useRef ( ) ;
103
102
const collapsedHeaderFiller : RefObject < HTMLDivElement > = useRef ( ) ;
104
- const expandedHeaderHeight = useRef ( 0 ) ;
103
+ const lastScrolledContainer = useRef ( ) ;
105
104
const hideHeaderButtonPressed = useRef ( false ) ;
106
- const stableOnScrollRef = useRef ( null ) ;
105
+ const stableContentOnScrollRef = useRef ( null ) ;
106
+ const stableBarOnScrollRef = useRef ( null ) ;
107
107
const scroller = useRef ( null ) ;
108
108
const [ scrollbarWidth , setScrollbarWidth ] = useState ( defaultScrollbarWidth ) ;
109
109
@@ -139,7 +139,7 @@ const ObjectPage: FC<ObjectPagePropTypes> = forwardRef((props: ObjectPagePropTyp
139
139
requestAnimationFrame ( ( ) => {
140
140
if ( ! objectPage . current ) {
141
141
// in case componentWillUnmount didn´t fire
142
- window . removeEventListener ( 'resize' , adjustDummyDivHeight ) ;
142
+ observer . current . disconnect ( ) ;
143
143
return ;
144
144
}
145
145
@@ -167,6 +167,8 @@ const ObjectPage: FC<ObjectPagePropTypes> = forwardRef((props: ObjectPagePropTyp
167
167
} ) ;
168
168
} ;
169
169
170
+ const observer = useRef ( new ResizeObserver ( adjustDummyDivHeight ) ) ;
171
+
170
172
const renderAnchorBar = ( ) => {
171
173
return (
172
174
< section className = { classes . anchorBar } role = "navigation" >
@@ -190,7 +192,6 @@ const ObjectPage: FC<ObjectPagePropTypes> = forwardRef((props: ObjectPagePropTyp
190
192
191
193
const changeHeader = useCallback ( ( ) => {
192
194
hideHeaderButtonPressed . current = true ;
193
- contentContainer . current . removeEventListener ( 'scroll' , onScroll ) ;
194
195
195
196
if ( ! expandHeaderActive && collapsedHeader ) {
196
197
setExpandHeaderActive ( true ) ;
@@ -342,9 +343,9 @@ const ObjectPage: FC<ObjectPagePropTypes> = forwardRef((props: ObjectPagePropTyp
342
343
343
344
// register resize handler
344
345
useEffect ( ( ) => {
345
- window . addEventListener ( 'resize' , adjustDummyDivHeight ) ;
346
- return window . removeEventListener ( 'resize' , adjustDummyDivHeight ) ;
347
- } , [ ] ) ;
346
+ observer . current . observe ( contentScrollContainer . current ) ;
347
+ return ( ) => observer . current . disconnect ( ) ;
348
+ } , [ adjustDummyDivHeight ] ) ;
348
349
349
350
useLayoutEffect ( ( ) => {
350
351
if ( ! isMounted ) return ;
@@ -376,86 +377,150 @@ const ObjectPage: FC<ObjectPagePropTypes> = forwardRef((props: ObjectPagePropTyp
376
377
}
377
378
} , [ selectedSectionIndex ] ) ;
378
379
379
- const getProportionateScrollTop = useCallback (
380
- ( base ) => {
381
- const contentContainerHeightFull = contentScrollContainer . current . getBoundingClientRect ( ) . height ;
382
- const scrollBarHeight = innerScrollBar . current . getBoundingClientRect ( ) . height ;
383
-
384
- return ( base / contentContainerHeightFull ) * scrollBarHeight ;
385
- } ,
386
- [ contentScrollContainer . current , innerScrollBar . current ]
387
- ) ;
380
+ const getProportionateScrollTop = useCallback ( ( activeContainer , passiveContainer , base ) => {
381
+ const activeHeight = activeContainer . current . getBoundingClientRect ( ) . height ;
382
+ const passiveHeight = passiveContainer . current . getBoundingClientRect ( ) . height ;
388
383
389
- const onScroll = useMemo ( ( ) => {
390
- if ( ! contentContainer . current ) return ;
384
+ return ( base / activeHeight ) * passiveHeight ;
385
+ } , [ ] ) ;
391
386
392
- if ( stableOnScrollRef . current ) {
393
- contentContainer . current . removeEventListener ( 'scroll' , stableOnScrollRef . current ) ;
387
+ const bindScrollEvent = useCallback ( ( scrollContainer , handler ) => {
388
+ if ( scrollContainer . current && handler . current ) {
389
+ scrollContainer . current . addEventListener ( 'scroll' , handler . current , { passive : true } ) ;
394
390
}
391
+ } , [ ] ) ;
395
392
396
- stableOnScrollRef . current = function innerOnScroll ( e ) {
397
- requestAnimationFrame ( ( ) => {
398
- if ( noHeader || alwaysShowContentHeader ) {
399
- scrollBar . current . scrollTop = getProportionateScrollTop ( e . target . scrollTop ) ;
400
- scroller . current . scroll ( e ) ;
401
- return ;
402
- }
393
+ const removeScrollEvent = useCallback ( ( scrollContainer , handler ) => {
394
+ if ( scrollContainer . current && handler . current ) {
395
+ scrollContainer . current . removeEventListener ( 'scroll' , handler . current ) ;
396
+ }
397
+ } , [ ] ) ;
403
398
399
+ const checkForHeaderCollapse = useCallback (
400
+ // activeContainer contains the scrollContainer thats being actively scrolled
401
+ // passiveContainer contains the container that needs to reflect activeContainers scroll position
402
+ ( activeContainer , activeInnerContainer , passiveContainer , passiveInnerContainer , e ) => {
403
+ if ( noHeader || alwaysShowContentHeader ) {
404
+ passiveContainer . current . scrollTop = alwaysShowContentHeader
405
+ ? e . target . scrollTop
406
+ : getProportionateScrollTop ( activeContainer , passiveContainer , e . target . scrollTop ) ;
407
+ scroller . current . scroll ( e ) ;
408
+ } else {
404
409
if ( expandHeaderActive ) {
405
410
setExpandHeaderActive ( false ) ;
406
411
}
407
- const innerHeaderHeight = innerHeader . current . getBoundingClientRect ( ) . height ;
408
- const threshold = collapsedHeader ? expandedHeaderHeight . current + 4 : innerHeaderHeight - 45 ;
409
- const shouldBeCollapsed = e . target . scrollTop > threshold ;
412
+
413
+ const threshold = 64 ;
414
+ const baseScrollValue =
415
+ activeContainer . current === contentContainer . current
416
+ ? e . target . scrollTop
417
+ : getProportionateScrollTop ( activeInnerContainer , passiveInnerContainer , e . target . scrollTop ) ;
418
+
419
+ const shouldBeCollapsed = baseScrollValue > threshold ;
410
420
if ( collapsedHeader !== shouldBeCollapsed ) {
411
- // contentContainer .current.removeEventListener('scroll', onScroll) ;
421
+ lastScrolledContainer . current = activeContainer . current ;
412
422
if ( shouldBeCollapsed ) {
413
- expandedHeaderHeight . current = innerHeaderHeight - 45 ;
414
- collapsedHeaderFiller . current . style . height = `${ expandedHeaderHeight . current } px` ;
423
+ collapsedHeaderFiller . current . style . height = `${ 64 } px` ;
415
424
} else {
416
425
collapsedHeaderFiller . current . style . height = `${ 0 } px` ;
417
426
}
427
+ lastScrolledContainer . current = activeContainer . current ;
428
+ removeScrollEvent ( contentContainer , stableContentOnScrollRef ) ;
429
+ removeScrollEvent ( scrollBar , stableBarOnScrollRef ) ;
418
430
setCollapsedHeader ( shouldBeCollapsed ) ;
419
431
} else {
420
- scrollBar . current . scrollTop = collapsedHeader
421
- ? e . target . scrollTop
422
- : getProportionateScrollTop ( e . target . scrollTop ) ;
432
+ const newScrollValue =
433
+ collapsedHeader && e . target . scrollTop > threshold + 50
434
+ ? e . target . scrollTop
435
+ : getProportionateScrollTop ( activeInnerContainer , passiveInnerContainer , e . target . scrollTop ) ;
436
+
437
+ passiveContainer . current . scrollTop = newScrollValue ;
423
438
scroller . current . scroll ( e ) ;
424
439
}
440
+ }
441
+ } ,
442
+ [
443
+ innerHeader . current ,
444
+ collapsedHeader ,
445
+ contentContainer . current ,
446
+ collapsedHeaderFiller . current ,
447
+ setCollapsedHeader ,
448
+ scrollBar . current ,
449
+ scroller . current
450
+ ]
451
+ ) ;
452
+
453
+ useEffect ( ( ) => {
454
+ if ( ! isMounted ) return ;
455
+ adjustDummyDivHeight ( ) . then ( ( ) => {
456
+ if ( ! hideHeaderButtonPressed . current ) {
457
+ removeScrollEvent ( contentContainer , stableContentOnScrollRef ) ;
458
+ removeScrollEvent ( scrollBar , stableBarOnScrollRef ) ;
459
+ if ( lastScrolledContainer . current === contentContainer . current ) {
460
+ contentContainer . current . scrollTop = collapsedHeader ? 64 + 2 : 64 - 2 ;
461
+ } else {
462
+ contentContainer . current . scrollTop = collapsedHeader ? 64 + 2 : 64 - 2 ;
463
+ scrollBar . current . scrollTop = getProportionateScrollTop (
464
+ contentScrollContainer ,
465
+ innerScrollBar ,
466
+ contentContainer . current . scrollTop
467
+ ) ;
468
+ }
469
+ requestAnimationFrame ( ( ) => {
470
+ bindScrollEvent ( contentContainer , stableContentOnScrollRef ) ;
471
+ bindScrollEvent ( scrollBar , stableBarOnScrollRef ) ;
472
+ } ) ;
473
+ }
474
+ hideHeaderButtonPressed . current = false ;
475
+ } ) ;
476
+ } , [ collapsedHeader ] ) ;
477
+
478
+ useEffect ( ( ) => {
479
+ if ( ! contentContainer . current ) return ;
480
+
481
+ removeScrollEvent ( contentContainer , stableContentOnScrollRef ) ;
482
+ removeScrollEvent ( scrollBar , stableBarOnScrollRef ) ;
483
+
484
+ stableContentOnScrollRef . current = function innerOnScroll ( e ) {
485
+ requestAnimationFrame ( ( ) => {
486
+ removeScrollEvent ( scrollBar , stableBarOnScrollRef ) ;
487
+ checkForHeaderCollapse ( contentContainer , contentScrollContainer , scrollBar , innerScrollBar , e ) ;
488
+ requestAnimationFrame ( ( ) => {
489
+ bindScrollEvent ( scrollBar , stableBarOnScrollRef ) ;
490
+ } ) ;
425
491
} ) ;
426
492
} ;
427
493
428
- contentContainer . current . addEventListener ( 'scroll' , stableOnScrollRef . current ) ;
494
+ stableBarOnScrollRef . current = function innerBarOnScroll ( e ) {
495
+ requestAnimationFrame ( ( ) => {
496
+ removeScrollEvent ( contentContainer , stableContentOnScrollRef ) ;
497
+ checkForHeaderCollapse ( scrollBar , innerScrollBar , contentContainer , contentScrollContainer , e ) ;
429
498
430
- return stableOnScrollRef . current ;
499
+ requestAnimationFrame ( ( ) => {
500
+ bindScrollEvent ( contentContainer , stableContentOnScrollRef ) ;
501
+ } ) ;
502
+ } ) ;
503
+ } ;
504
+
505
+ bindScrollEvent ( contentContainer , stableContentOnScrollRef ) ;
506
+ bindScrollEvent ( scrollBar , stableBarOnScrollRef ) ;
431
507
} , [
432
508
noHeader ,
509
+ checkForHeaderCollapse ,
433
510
alwaysShowContentHeader ,
434
511
scrollBar . current ,
512
+ innerScrollBar . current ,
435
513
innerHeader . current ,
436
514
contentContainer . current ,
437
- expandedHeaderHeight . current ,
515
+ contentScrollContainer . current ,
438
516
collapsedHeaderFiller . current ,
439
517
collapsedHeader ,
440
518
setCollapsedHeader ,
441
519
expandHeaderActive ,
442
520
getProportionateScrollTop
443
521
] ) ;
444
522
445
- useLayoutEffect ( ( ) => {
446
- if ( ! isMounted ) return ;
447
- adjustDummyDivHeight ( ) . then ( ( ) => {
448
- if ( ! hideHeaderButtonPressed . current ) {
449
- const innerHeaderHeight = innerHeader . current . getBoundingClientRect ( ) . height ;
450
- const base = collapsedHeader ? expandedHeaderHeight . current + 5 : innerHeaderHeight - 50 ;
451
- contentContainer . current . scrollTop = base ;
452
- scrollBar . current . scrollTop = collapsedHeader ? base : getProportionateScrollTop ( base ) ;
453
- }
454
- hideHeaderButtonPressed . current = false ;
455
- } ) ;
456
- } , [ collapsedHeader ] ) ;
457
-
458
- useLayoutEffect ( ( ) => {
523
+ useEffect ( ( ) => {
459
524
if ( ! isMounted ) return ;
460
525
adjustDummyDivHeight ( ) ;
461
526
} , [ expandHeaderActive ] ) ;
0 commit comments