@@ -13,7 +13,6 @@ import { clsx } from 'clsx';
13
13
import type { CSSProperties , ReactElement , ReactNode } from 'react' ;
14
14
import { cloneElement , forwardRef , isValidElement , useCallback , useEffect , useMemo , useRef , useState } from 'react' ;
15
15
import { ObjectPageMode } from '../../enums/index.js' ;
16
- import { addCustomCSSWithScoping } from '../../internal/addCustomCSSWithScoping.js' ;
17
16
import { safeGetChildrenArray } from '../../internal/safeGetChildrenArray.js' ;
18
17
import { useObserveHeights } from '../../internal/useObserveHeights.js' ;
19
18
import type { CommonProps , Ui5CustomEvent } from '../../types/index.js' ;
@@ -32,17 +31,7 @@ import type {
32
31
} from '../ObjectPageTitle/index.js' ;
33
32
import { CollapsedAvatar } from './CollapsedAvatar.js' ;
34
33
import { classNames , styleData } from './ObjectPage.module.css.js' ;
35
- import { extractSectionIdFromHtmlId , getSectionById } from './ObjectPageUtils.js' ;
36
-
37
- addCustomCSSWithScoping (
38
- 'ui5-tabcontainer' ,
39
- // todo: the additional text span adds 3px to the container - needs to be investigated why
40
- `
41
- :host([data-component-name="ObjectPageTabContainer"]) [id$="additionalText"] {
42
- display: none;
43
- }
44
- `
45
- ) ;
34
+ import { getSectionById } from './ObjectPageUtils.js' ;
46
35
47
36
const ObjectPageCssVariables = {
48
37
headerDisplay : '--_ui5wcr_ObjectPage_header_display' ,
@@ -239,7 +228,6 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
239
228
const anchorBarRef = useRef < HTMLDivElement > ( null ) ;
240
229
const objectPageContentRef = useRef < HTMLDivElement > ( null ) ;
241
230
const selectionScrollTimeout = useRef ( null ) ;
242
- const [ isAfterScroll , setIsAfterScroll ] = useState ( false ) ;
243
231
const isToggledRef = useRef ( false ) ;
244
232
const [ headerCollapsedInternal , setHeaderCollapsedInternal ] = useState < undefined | boolean > ( undefined ) ;
245
233
const [ scrolledHeaderExpanded , setScrolledHeaderExpanded ] = useState ( false ) ;
@@ -256,7 +244,7 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
256
244
257
245
const prevInternalSelectedSectionId = useRef ( internalSelectedSectionId ) ;
258
246
const fireOnSelectedChangedEvent = ( targetEvent , index , id , section ) => {
259
- if ( typeof onSelectedSectionChange === 'function' && prevInternalSelectedSectionId . current !== id ) {
247
+ if ( typeof onSelectedSectionChange === 'function' && targetEvent && prevInternalSelectedSectionId . current !== id ) {
260
248
onSelectedSectionChange (
261
249
enrichEventWithDetails ( targetEvent , {
262
250
selectedSectionIndex : parseInt ( index , 10 ) ,
@@ -344,7 +332,7 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
344
332
safeTopHeaderHeight +
345
333
anchorBarHeight +
346
334
TAB_CONTAINER_HEADER_HEIGHT +
347
- ( headerPinned ? headerContentHeight : 0 ) +
335
+ ( headerPinned && ! headerCollapsed ? headerContentHeight : 0 ) +
348
336
'px' ;
349
337
section . focus ( ) ;
350
338
section . scrollIntoView ( { behavior : 'smooth' } ) ;
@@ -558,76 +546,53 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
558
546
559
547
const { onScroll : _0 , selectedSubSectionId : _1 , ...propsWithoutOmitted } = rest ;
560
548
549
+ const visibleSectionIds = useRef < Set < string > > ( new Set ( ) ) ;
561
550
useEffect ( ( ) => {
562
551
const sectionNodes = objectPageRef . current ?. querySelectorAll ( 'section[data-component-name="ObjectPageSection"]' ) ;
563
- const objectPageHeight = objectPageRef . current ?. clientHeight ?? 1000 ;
564
- const marginBottom = objectPageHeight - totalHeaderHeight - /*TabContainer*/ TAB_CONTAINER_HEADER_HEIGHT ;
565
- const rootMargin = `- ${ totalHeaderHeight } px 0px - ${ marginBottom < 0 ? 0 : marginBottom } px 0px` ;
552
+ // only the sticky part of the header must be added as margin
553
+ const rootMargin = `- ${ ( headerPinned && ! headerCollapsed ? totalHeaderHeight : topHeaderHeight ) + TAB_CONTAINER_HEADER_HEIGHT } px 0px 0px 0px` ;
554
+
566
555
const observer = new IntersectionObserver (
567
- ( [ section ] ) => {
568
- if ( section . isIntersecting && isProgrammaticallyScrolled . current === false ) {
569
- if (
570
- objectPageRef . current . getBoundingClientRect ( ) . top + totalHeaderHeight + TAB_CONTAINER_HEADER_HEIGHT <=
571
- section . target . getBoundingClientRect ( ) . bottom
572
- ) {
573
- const currentId = extractSectionIdFromHtmlId ( section . target . id ) ;
574
- setInternalSelectedSectionId ( currentId ) ;
575
- const currentIndex = safeGetChildrenArray ( children ) . findIndex ( ( objectPageSection ) => {
576
- return (
577
- isValidElement ( objectPageSection ) &&
578
- ( objectPageSection as ReactElement < ObjectPageSectionPropTypes > ) . props ?. id === currentId
579
- ) ;
580
- } ) ;
581
- debouncedOnSectionChange ( scrollEvent . current , currentIndex , currentId , section . target ) ;
556
+ ( entries ) => {
557
+ entries . forEach ( ( entry ) => {
558
+ const sectionId = entry . target . id ;
559
+ if ( entry . isIntersecting ) {
560
+ visibleSectionIds . current . add ( sectionId ) ;
561
+ } else {
562
+ visibleSectionIds . current . delete ( sectionId ) ;
582
563
}
583
- }
564
+
565
+ let currentIndex : undefined | number ;
566
+ const sortedVisibleSections = Array . from ( sectionNodes ) . filter ( ( section , index ) => {
567
+ const isVisibleSection = visibleSectionIds . current . has ( section . id ) ;
568
+ if ( currentIndex === undefined && isVisibleSection ) {
569
+ currentIndex = index ;
570
+ }
571
+ return visibleSectionIds . current . has ( section . id ) ;
572
+ } ) ;
573
+
574
+ if ( sortedVisibleSections . length > 0 ) {
575
+ const section = sortedVisibleSections [ 0 ] ;
576
+ const id = sortedVisibleSections [ 0 ] . id . slice ( 18 ) ;
577
+ setInternalSelectedSectionId ( id ) ;
578
+ debouncedOnSectionChange ( scrollEvent . current , currentIndex , id , section ) ;
579
+ }
580
+ } ) ;
584
581
} ,
585
582
{
586
583
root : objectPageRef . current ,
587
584
rootMargin,
588
585
threshold : [ 0 ]
589
586
}
590
587
) ;
591
-
592
588
sectionNodes . forEach ( ( el ) => {
593
589
observer . observe ( el ) ;
594
590
} ) ;
595
591
596
592
return ( ) => {
597
593
observer . disconnect ( ) ;
598
594
} ;
599
- } , [ children , totalHeaderHeight , setInternalSelectedSectionId , isProgrammaticallyScrolled ] ) ;
600
-
601
- // Fallback when scrolling faster than the IntersectionObserver can observe (in most cases faster than 60fps)
602
- useEffect ( ( ) => {
603
- const sectionNodes = objectPageRef . current ?. querySelectorAll ( 'section[data-component-name="ObjectPageSection"]' ) ;
604
- if ( isAfterScroll ) {
605
- let currentSection = sectionNodes [ sectionNodes . length - 1 ] ;
606
- let currentIndex : number ;
607
- for ( let i = 0 ; i <= sectionNodes . length - 1 ; i ++ ) {
608
- const sectionNode = sectionNodes [ i ] ;
609
- if (
610
- objectPageRef . current . getBoundingClientRect ( ) . top + totalHeaderHeight + TAB_CONTAINER_HEADER_HEIGHT <=
611
- sectionNode . getBoundingClientRect ( ) . bottom
612
- ) {
613
- currentSection = sectionNode ;
614
- currentIndex = i ;
615
- break ;
616
- }
617
- }
618
- const currentSectionId = extractSectionIdFromHtmlId ( currentSection ?. id ) ;
619
- if ( currentSectionId !== internalSelectedSectionId ) {
620
- setInternalSelectedSectionId ( currentSectionId ) ;
621
- debouncedOnSectionChange (
622
- scrollEvent . current ,
623
- currentIndex ?? sectionNodes . length - 1 ,
624
- currentSectionId ,
625
- currentSection
626
- ) ;
627
- }
628
- setIsAfterScroll ( false ) ;
629
- }
630
- } , [ isAfterScroll ] ) ;
595
+ } , [ children , totalHeaderHeight , setInternalSelectedSectionId , headerPinned , debouncedOnSectionChange ] ) ;
631
596
632
597
const onTitleClick = ( e ) => {
633
598
e . stopPropagation ( ) ;
@@ -721,9 +686,6 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
721
686
if ( selectionScrollTimeout . current ) {
722
687
clearTimeout ( selectionScrollTimeout . current ) ;
723
688
}
724
- selectionScrollTimeout . current = setTimeout ( ( ) => {
725
- setIsAfterScroll ( true ) ;
726
- } , 100 ) ;
727
689
if ( ! headerPinned || e . target . scrollTop === 0 ) {
728
690
objectPageRef . current ?. classList . remove ( classNames . headerCollapsed ) ;
729
691
}
@@ -894,7 +856,7 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
894
856
</ div >
895
857
) }
896
858
< div data-component-name = "ObjectPageContent" className = { classNames . content } ref = { objectPageContentRef } >
897
- < div style = { { height : headerCollapsed ? `${ headerContentHeight } px` : 0 } } aria-hidden />
859
+ < div style = { { height : headerCollapsed && ! headerPinned ? `${ headerContentHeight } px` : 0 } } aria-hidden />
898
860
{ placeholder ? placeholder : sections }
899
861
< div style = { { height : `${ sectionSpacer } px` } } aria-hidden />
900
862
</ div >
0 commit comments