@@ -25,7 +25,7 @@ import { DynamicPageHeader } from '../DynamicPageHeader/index.js';
25
25
import type { ObjectPageSectionPropTypes } from '../ObjectPageSection/index.js' ;
26
26
import { CollapsedAvatar } from './CollapsedAvatar.js' ;
27
27
import { classNames , styleData } from './ObjectPage.module.css.js' ;
28
- import { extractSectionIdFromHtmlId , getSectionById } from './ObjectPageUtils.js' ;
28
+ import { getSectionById } from './ObjectPageUtils.js' ;
29
29
30
30
addCustomCSSWithScoping (
31
31
'ui5-tabcontainer' ,
@@ -216,7 +216,6 @@ const ObjectPage = forwardRef<HTMLDivElement, ObjectPagePropTypes>((props, ref)
216
216
const anchorBarRef = useRef < HTMLDivElement > ( null ) ;
217
217
const objectPageContentRef = useRef < HTMLDivElement > ( null ) ;
218
218
const selectionScrollTimeout = useRef ( null ) ;
219
- const [ isAfterScroll , setIsAfterScroll ] = useState ( false ) ;
220
219
const isToggledRef = useRef ( false ) ;
221
220
const [ headerCollapsedInternal , setHeaderCollapsedInternal ] = useState < undefined | boolean > ( undefined ) ;
222
221
const [ scrolledHeaderExpanded , setScrolledHeaderExpanded ] = useState ( false ) ;
@@ -245,7 +244,7 @@ const ObjectPage = forwardRef<HTMLDivElement, ObjectPagePropTypes>((props, ref)
245
244
246
245
const prevInternalSelectedSectionId = useRef ( internalSelectedSectionId ) ;
247
246
const fireOnSelectedChangedEvent = ( targetEvent , index , id , section ) => {
248
- if ( typeof onSelectedSectionChange === 'function' && prevInternalSelectedSectionId . current !== id ) {
247
+ if ( typeof onSelectedSectionChange === 'function' && targetEvent && prevInternalSelectedSectionId . current !== id ) {
249
248
onSelectedSectionChange (
250
249
enrichEventWithDetails ( targetEvent , {
251
250
selectedSectionIndex : parseInt ( index , 10 ) ,
@@ -318,7 +317,7 @@ const ObjectPage = forwardRef<HTMLDivElement, ObjectPagePropTypes>((props, ref)
318
317
safeTopHeaderHeight +
319
318
anchorBarHeight +
320
319
TAB_CONTAINER_HEADER_HEIGHT +
321
- ( headerPinned ? headerContentHeight : 0 ) +
320
+ ( headerPinned && ! headerCollapsed ? headerContentHeight : 0 ) +
322
321
'px' ;
323
322
section . focus ( ) ;
324
323
section . scrollIntoView ( { behavior : 'smooth' } ) ;
@@ -527,73 +526,53 @@ const ObjectPage = forwardRef<HTMLDivElement, ObjectPagePropTypes>((props, ref)
527
526
528
527
const { onScroll : _0 , selectedSubSectionId : _1 , ...propsWithoutOmitted } = rest ;
529
528
529
+ const visibleSectionIds = useRef < Set < string > > ( new Set ( ) ) ;
530
530
useEffect ( ( ) => {
531
531
const sectionNodes = objectPageRef . current ?. querySelectorAll ( 'section[data-component-name="ObjectPageSection"]' ) ;
532
- const objectPageHeight = objectPageRef . current ?. clientHeight ?? 1000 ;
533
- const marginBottom = objectPageHeight - totalHeaderHeight - /*TabContainer*/ TAB_CONTAINER_HEADER_HEIGHT ;
534
- const rootMargin = `- ${ totalHeaderHeight } px 0px - ${ marginBottom < 0 ? 0 : marginBottom } px 0px` ;
532
+ // only the sticky part of the header must be added as margin
533
+ const rootMargin = `- ${ ( headerPinned && ! headerCollapsed ? totalHeaderHeight : topHeaderHeight ) + TAB_CONTAINER_HEADER_HEIGHT } px 0px 0px 0px` ;
534
+
535
535
const observer = new IntersectionObserver (
536
- ( [ section ] ) => {
537
- if ( section . isIntersecting && isProgrammaticallyScrolled . current === false ) {
538
- if (
539
- objectPageRef . current . getBoundingClientRect ( ) . top + totalHeaderHeight + TAB_CONTAINER_HEADER_HEIGHT <=
540
- section . target . getBoundingClientRect ( ) . bottom
541
- ) {
542
- const currentId = extractSectionIdFromHtmlId ( section . target . id ) ;
543
- setInternalSelectedSectionId ( currentId ) ;
544
- const currentIndex = safeGetChildrenArray ( children ) . findIndex ( ( objectPageSection ) => {
545
- return isValidElement ( objectPageSection ) && objectPageSection . props ?. id === currentId ;
546
- } ) ;
547
- debouncedOnSectionChange ( scrollEvent . current , currentIndex , currentId , section . target ) ;
536
+ ( entries ) => {
537
+ entries . forEach ( ( entry ) => {
538
+ const sectionId = entry . target . id ;
539
+ if ( entry . isIntersecting ) {
540
+ visibleSectionIds . current . add ( sectionId ) ;
541
+ } else {
542
+ visibleSectionIds . current . delete ( sectionId ) ;
548
543
}
549
- }
544
+
545
+ let currentIndex : undefined | number ;
546
+ const sortedVisibleSections = Array . from ( sectionNodes ) . filter ( ( section , index ) => {
547
+ const isVisibleSection = visibleSectionIds . current . has ( section . id ) ;
548
+ if ( currentIndex === undefined && isVisibleSection ) {
549
+ currentIndex = index ;
550
+ }
551
+ return visibleSectionIds . current . has ( section . id ) ;
552
+ } ) ;
553
+
554
+ if ( sortedVisibleSections . length > 0 ) {
555
+ const section = sortedVisibleSections [ 0 ] ;
556
+ const id = sortedVisibleSections [ 0 ] . id . slice ( 18 ) ;
557
+ setInternalSelectedSectionId ( id ) ;
558
+ debouncedOnSectionChange ( scrollEvent . current , currentIndex , id , section ) ;
559
+ }
560
+ } ) ;
550
561
} ,
551
562
{
552
563
root : objectPageRef . current ,
553
564
rootMargin,
554
565
threshold : [ 0 ]
555
566
}
556
567
) ;
557
-
558
568
sectionNodes . forEach ( ( el ) => {
559
569
observer . observe ( el ) ;
560
570
} ) ;
561
571
562
572
return ( ) => {
563
573
observer . disconnect ( ) ;
564
574
} ;
565
- } , [ children , totalHeaderHeight , setInternalSelectedSectionId , isProgrammaticallyScrolled ] ) ;
566
-
567
- // Fallback when scrolling faster than the IntersectionObserver can observe (in most cases faster than 60fps)
568
- useEffect ( ( ) => {
569
- const sectionNodes = objectPageRef . current ?. querySelectorAll ( 'section[data-component-name="ObjectPageSection"]' ) ;
570
- if ( isAfterScroll ) {
571
- let currentSection = sectionNodes [ sectionNodes . length - 1 ] ;
572
- let currentIndex : number ;
573
- for ( let i = 0 ; i <= sectionNodes . length - 1 ; i ++ ) {
574
- const sectionNode = sectionNodes [ i ] ;
575
- if (
576
- objectPageRef . current . getBoundingClientRect ( ) . top + totalHeaderHeight + TAB_CONTAINER_HEADER_HEIGHT <=
577
- sectionNode . getBoundingClientRect ( ) . bottom
578
- ) {
579
- currentSection = sectionNode ;
580
- currentIndex = i ;
581
- break ;
582
- }
583
- }
584
- const currentSectionId = extractSectionIdFromHtmlId ( currentSection ?. id ) ;
585
- if ( currentSectionId !== internalSelectedSectionId ) {
586
- setInternalSelectedSectionId ( currentSectionId ) ;
587
- debouncedOnSectionChange (
588
- scrollEvent . current ,
589
- currentIndex ?? sectionNodes . length - 1 ,
590
- currentSectionId ,
591
- currentSection
592
- ) ;
593
- }
594
- setIsAfterScroll ( false ) ;
595
- }
596
- } , [ isAfterScroll ] ) ;
575
+ } , [ children , totalHeaderHeight , setInternalSelectedSectionId , headerPinned , debouncedOnSectionChange ] ) ;
597
576
598
577
const titleHeaderNotClickable =
599
578
( alwaysShowContentHeader && ! headerContentPinnable ) ||
@@ -744,9 +723,6 @@ const ObjectPage = forwardRef<HTMLDivElement, ObjectPagePropTypes>((props, ref)
744
723
if ( selectionScrollTimeout . current ) {
745
724
clearTimeout ( selectionScrollTimeout . current ) ;
746
725
}
747
- selectionScrollTimeout . current = setTimeout ( ( ) => {
748
- setIsAfterScroll ( true ) ;
749
- } , 100 ) ;
750
726
if ( ! headerPinned || e . target . scrollTop === 0 ) {
751
727
objectPageRef . current ?. classList . remove ( classNames . headerCollapsed ) ;
752
728
}
@@ -907,7 +883,7 @@ const ObjectPage = forwardRef<HTMLDivElement, ObjectPagePropTypes>((props, ref)
907
883
</ div >
908
884
) }
909
885
< div data-component-name = "ObjectPageContent" className = { classNames . content } ref = { objectPageContentRef } >
910
- < div style = { { height : headerCollapsed ? `${ headerContentHeight } px` : 0 } } aria-hidden />
886
+ < div style = { { height : headerCollapsed && ! headerPinned ? `${ headerContentHeight } px` : 0 } } aria-hidden />
911
887
{ placeholder ? placeholder : sections }
912
888
< div style = { { height : `${ sectionSpacer } px` } } aria-hidden />
913
889
</ div >
0 commit comments