@@ -25,7 +25,7 @@ import { DynamicPageHeader } from '../DynamicPageHeader/index.js';
2525import type { ObjectPageSectionPropTypes } from '../ObjectPageSection/index.js' ;
2626import { CollapsedAvatar } from './CollapsedAvatar.js' ;
2727import { classNames , styleData } from './ObjectPage.module.css.js' ;
28- import { extractSectionIdFromHtmlId , getSectionById } from './ObjectPageUtils.js' ;
28+ import { getSectionById } from './ObjectPageUtils.js' ;
2929
3030addCustomCSSWithScoping (
3131 'ui5-tabcontainer' ,
@@ -216,7 +216,6 @@ const ObjectPage = forwardRef<HTMLDivElement, ObjectPagePropTypes>((props, ref)
216216 const anchorBarRef = useRef < HTMLDivElement > ( null ) ;
217217 const objectPageContentRef = useRef < HTMLDivElement > ( null ) ;
218218 const selectionScrollTimeout = useRef ( null ) ;
219- const [ isAfterScroll , setIsAfterScroll ] = useState ( false ) ;
220219 const isToggledRef = useRef ( false ) ;
221220 const [ headerCollapsedInternal , setHeaderCollapsedInternal ] = useState < undefined | boolean > ( undefined ) ;
222221 const [ scrolledHeaderExpanded , setScrolledHeaderExpanded ] = useState ( false ) ;
@@ -245,7 +244,7 @@ const ObjectPage = forwardRef<HTMLDivElement, ObjectPagePropTypes>((props, ref)
245244
246245 const prevInternalSelectedSectionId = useRef ( internalSelectedSectionId ) ;
247246 const fireOnSelectedChangedEvent = ( targetEvent , index , id , section ) => {
248- if ( typeof onSelectedSectionChange === 'function' && prevInternalSelectedSectionId . current !== id ) {
247+ if ( typeof onSelectedSectionChange === 'function' && targetEvent && prevInternalSelectedSectionId . current !== id ) {
249248 onSelectedSectionChange (
250249 enrichEventWithDetails ( targetEvent , {
251250 selectedSectionIndex : parseInt ( index , 10 ) ,
@@ -318,7 +317,7 @@ const ObjectPage = forwardRef<HTMLDivElement, ObjectPagePropTypes>((props, ref)
318317 safeTopHeaderHeight +
319318 anchorBarHeight +
320319 TAB_CONTAINER_HEADER_HEIGHT +
321- ( headerPinned ? headerContentHeight : 0 ) +
320+ ( headerPinned && ! headerCollapsed ? headerContentHeight : 0 ) +
322321 'px' ;
323322 section . focus ( ) ;
324323 section . scrollIntoView ( { behavior : 'smooth' } ) ;
@@ -527,73 +526,53 @@ const ObjectPage = forwardRef<HTMLDivElement, ObjectPagePropTypes>((props, ref)
527526
528527 const { onScroll : _0 , selectedSubSectionId : _1 , ...propsWithoutOmitted } = rest ;
529528
529+ const visibleSectionIds = useRef < Set < string > > ( new Set ( ) ) ;
530530 useEffect ( ( ) => {
531531 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+
535535 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 ) ;
548543 }
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+ } ) ;
550561 } ,
551562 {
552563 root : objectPageRef . current ,
553564 rootMargin,
554565 threshold : [ 0 ]
555566 }
556567 ) ;
557-
558568 sectionNodes . forEach ( ( el ) => {
559569 observer . observe ( el ) ;
560570 } ) ;
561571
562572 return ( ) => {
563573 observer . disconnect ( ) ;
564574 } ;
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 ] ) ;
597576
598577 const titleHeaderNotClickable =
599578 ( alwaysShowContentHeader && ! headerContentPinnable ) ||
@@ -744,9 +723,6 @@ const ObjectPage = forwardRef<HTMLDivElement, ObjectPagePropTypes>((props, ref)
744723 if ( selectionScrollTimeout . current ) {
745724 clearTimeout ( selectionScrollTimeout . current ) ;
746725 }
747- selectionScrollTimeout . current = setTimeout ( ( ) => {
748- setIsAfterScroll ( true ) ;
749- } , 100 ) ;
750726 if ( ! headerPinned || e . target . scrollTop === 0 ) {
751727 objectPageRef . current ?. classList . remove ( classNames . headerCollapsed ) ;
752728 }
@@ -907,7 +883,7 @@ const ObjectPage = forwardRef<HTMLDivElement, ObjectPagePropTypes>((props, ref)
907883 </ div >
908884 ) }
909885 < 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 />
911887 { placeholder ? placeholder : sections }
912888 < div style = { { height : `${ sectionSpacer } px` } } aria-hidden />
913889 </ div >
0 commit comments