@@ -6,7 +6,7 @@ import InputType from '@ui5/webcomponents/dist/types/InputType.js';
66import TitleLevel from '@ui5/webcomponents/dist/types/TitleLevel.js' ;
77import ValueState from '@ui5/webcomponents-base/dist/types/ValueState.js' ;
88import IllustrationMessageType from '@ui5/webcomponents-fiori/dist/types/IllustrationMessageType.js' ;
9- import { useEffect , useLayoutEffect , useReducer , useRef , useState } from 'react' ;
9+ import { useEffect , useLayoutEffect , useReducer , useRef , useState , version as reactVersion } from 'react' ;
1010import type { CSSProperties } from 'react' ;
1111import type { ObjectPagePropTypes } from '../..' ;
1212import {
@@ -114,7 +114,7 @@ describe('ObjectPage', () => {
114114 cy . get ( '[ui5-tabcontainer]' ) . findUi5TabByText ( 'Section 15' ) . should ( 'have.attr' , 'aria-selected' , 'true' ) ;
115115
116116 if ( mode === ObjectPageMode . Default ) {
117- cy . findByTestId ( 'op' ) . scrollTo ( 0 , 4750 ) ;
117+ cy . findByTestId ( 'op' ) . scrollTo ( 0 , 4858 ) ;
118118
119119 cy . findByText ( 'Content 7' ) . should ( 'be.visible' ) ;
120120 cy . get ( '[ui5-tabcontainer]' ) . findUi5TabByText ( 'Section 7' ) . should ( 'have.attr' , 'aria-selected' , 'true' ) ;
@@ -124,7 +124,7 @@ describe('ObjectPage', () => {
124124 for ( let i = 0 ; i < 15 ; i ++ ) {
125125 cy . findByText ( 'Add' ) . click ( ) ;
126126 }
127- cy . findByTestId ( 'op' ) . scrollTo ( 0 , 4750 ) ;
127+ cy . findByTestId ( 'op' ) . scrollTo ( 0 , 4858 ) ;
128128
129129 cy . findByText ( 'Content 7' ) . should ( 'be.visible' ) ;
130130 cy . get ( '[ui5-tabcontainer]' ) . findUi5TabByText ( 'Section 7' ) . should ( 'have.attr' , 'aria-selected' , 'true' ) ;
@@ -374,12 +374,6 @@ describe('ObjectPage', () => {
374374 ) ;
375375 cy . wait ( 200 ) ;
376376
377- // first titleText should never be displayed (not.be.visible doesn't work here - only invisible for sighted users)
378- cy . findByText ( 'Goals' )
379- . parent ( )
380- . should ( 'have.css' , 'width' , '1px' )
381- . and ( 'have.css' , 'margin' , '-1px' )
382- . and ( 'have.css' , 'position' , 'absolute' ) ;
383377 cy . findByText ( 'Employment' ) . should ( 'not.be.visible' ) ;
384378 cy . findByText ( 'Test' ) . should ( 'be.visible' ) ;
385379
@@ -712,19 +706,19 @@ describe('ObjectPage', () => {
712706 } ;
713707 cy . mount ( < TestComp height = "2000px" mode = { ObjectPageMode . Default } /> ) ;
714708 cy . findByText ( 'Update Heights' ) . click ( ) ;
715- cy . findByText ( '{"offset":1080,"scroll":2290 }' ) . should ( 'exist' ) ;
709+ cy . findByText ( '{"offset":1080,"scroll":2330 }' ) . should ( 'exist' ) ;
716710
717711 cy . findByTestId ( 'op' ) . scrollTo ( 'bottom' ) ;
718712 cy . findByText ( 'Update Heights' ) . click ( { force : true } ) ;
719- cy . findByText ( '{"offset":1080,"scroll":2290 }' ) . should ( 'exist' ) ;
713+ cy . findByText ( '{"offset":1080,"scroll":2330 }' ) . should ( 'exist' ) ;
720714
721715 cy . mount ( < TestComp height = "2000px" withFooter mode = { ObjectPageMode . Default } /> ) ;
722716 cy . findByText ( 'Update Heights' ) . click ( ) ;
723- cy . findByText ( '{"offset":1080,"scroll":2330 }' ) . should ( 'exist' ) ;
717+ cy . findByText ( '{"offset":1080,"scroll":2370 }' ) . should ( 'exist' ) ;
724718
725719 cy . findByTestId ( 'op' ) . scrollTo ( 'bottom' ) ;
726720 cy . findByText ( 'Update Heights' ) . click ( { force : true } ) ;
727- cy . findByText ( '{"offset":1080,"scroll":2330 }' ) . should ( 'exist' ) ;
721+ cy . findByText ( '{"offset":1080,"scroll":2370 }' ) . should ( 'exist' ) ;
728722
729723 cy . mount ( < TestComp height = "400px" mode = { ObjectPageMode . Default } /> ) ;
730724 cy . findByText ( 'Update Heights' ) . click ( ) ;
@@ -923,12 +917,6 @@ describe('ObjectPage', () => {
923917 cy . get ( '[ui5-tabcontainer]' ) . findUi5TabByText ( 'Goals' ) . click ( ) ;
924918 cy . findByText ( 'Custom Header Section One' ) . should ( 'be.visible' ) ;
925919 cy . findByText ( 'toggle titleText1' ) . click ( { scrollBehavior : false , force : true } ) ;
926- // first titleText should never be displayed (not.be.visible doesn't work here - only invisible for sighted users)
927- cy . findByText ( 'Goals' )
928- . parent ( )
929- . should ( 'have.css' , 'width' , '1px' )
930- . and ( 'have.css' , 'margin' , '-1px' )
931- . and ( 'have.css' , 'position' , 'absolute' ) ;
932920 cy . findByText ( 'Custom Header Section One' ) . should ( 'be.visible' ) ;
933921
934922 cy . get ( '[ui5-tabcontainer]' ) . findUi5TabByText ( 'Personal' ) . click ( ) ;
@@ -1853,6 +1841,61 @@ describe('ObjectPage', () => {
18531841 }
18541842 cy . focused ( ) . should ( 'be.visible' ) . and ( 'have.attr' , 'ui5-table-row' ) ;
18551843 } ) ;
1844+
1845+ it ( 'sticky headers' , ( ) => {
1846+ cy . mount (
1847+ < ObjectPage
1848+ titleArea = { DPTitle }
1849+ headerArea = { DPContent }
1850+ mode = "IconTabBar"
1851+ style = { { height : '1000px' } }
1852+ data-testid = "op"
1853+ >
1854+ { OPContent }
1855+ { OPContentWithCustomHeaderSections }
1856+ </ ObjectPage > ,
1857+ ) ;
1858+
1859+ cy . findByText ( 'Goals' ) . should ( 'not.be.visible' ) ;
1860+ cy . get ( '[ui5-tabcontainer]' ) . findUi5TabByText ( 'Employment' ) . click ( ) ;
1861+ cy . findByText ( 'Employment' ) . should ( 'not.be.visible' ) ;
1862+ cy . findByText ( 'Employee Details' ) . parent ( ) . should ( 'have.css' , 'position' , 'sticky' ) ;
1863+
1864+ cy . mount (
1865+ < ObjectPage
1866+ titleArea = { DPTitle }
1867+ headerArea = { DPContent }
1868+ // scrollBehavior "auto" prevents flaky behavior when test is run with React18
1869+ style = { { height : '1000px' , scrollBehavior : reactVersion . startsWith ( '18' ) ? 'auto' : 'smooth' } }
1870+ data-testid = "op"
1871+ >
1872+ { OPContent }
1873+ { OPContentWithCustomHeaderSections }
1874+ </ ObjectPage > ,
1875+ ) ;
1876+
1877+ cy . findByText ( 'Goals' ) . should ( 'be.visible' ) . parent ( ) . should ( 'have.css' , 'position' , 'sticky' ) ;
1878+ cy . findByTestId ( 'op' ) . scrollTo ( 0 , 500 ) ;
1879+ cy . findByText ( 'Goals' ) . should ( 'be.visible' ) ;
1880+ cy . get ( '[ui5-tabcontainer]' ) . findUi5TabByText ( 'Personal' ) . click ( ) ;
1881+ // has subsections -> only subsection headers are sticky
1882+ cy . findByText ( 'Personal' ) . should ( 'be.visible' ) . parent ( ) . should ( 'have.css' , 'position' , 'static' ) ;
1883+ cy . findByText ( 'Connect' ) . should ( 'be.visible' ) . parent ( ) . should ( 'have.css' , 'position' , 'sticky' ) ;
1884+ cy . findByTestId ( 'op' ) . scrollTo ( 0 , 2500 ) ;
1885+ cy . findByText ( 'Goals' ) . should ( 'not.be.visible' ) ;
1886+ cy . findByText ( 'Payment Information' ) . should ( 'be.visible' ) ;
1887+ cy . get ( '[ui5-tabcontainer]' ) . findUi5TabByText ( 'Custom Header Section One' ) . click ( ) ;
1888+ cy . findByText ( 'Custom Header Section One' ) . should ( 'be.visible' ) . parent ( ) . should ( 'have.css' , 'position' , 'sticky' ) ;
1889+ cy . findByTestId ( 'op' ) . scrollTo ( 0 , 3500 ) ;
1890+ cy . findByText ( 'Custom Header Section One' ) . should ( 'be.visible' ) ;
1891+ cy . get ( '[ui5-tabcontainer]' ) . findUi5TabByText ( 'Custom Header Section Two' ) . click ( ) ;
1892+ // has subsections -> only subsection headers are sticky
1893+ cy . findByText ( 'Custom Header Section Two' ) . should ( 'be.visible' ) . parent ( ) . should ( 'have.css' , 'position' , 'static' ) ;
1894+ cy . findByText ( 'Subsection1' ) . should ( 'be.visible' ) . parent ( ) . should ( 'have.css' , 'position' , 'sticky' ) ;
1895+ cy . findByTestId ( 'op' ) . scrollTo ( 0 , 4000 ) ;
1896+ cy . findByText ( 'Custom Header Section Two' ) . should ( 'not.be.visible' ) ;
1897+ cy . findByText ( 'Subsection1' ) . should ( 'be.visible' ) ;
1898+ } ) ;
18561899} ) ;
18571900
18581901const DPTitle = (
@@ -1952,6 +1995,44 @@ const OPContent = [
19521995 </ ObjectPageSection > ,
19531996] ;
19541997
1998+ const OPContentWithCustomHeaderSections = [
1999+ < ObjectPageSection
2000+ key = { 'customheader1' }
2001+ titleText = "Custom Header Section One"
2002+ hideTitleText
2003+ id = "custom1"
2004+ header = { < Title > Custom Header Section One</ Title > }
2005+ >
2006+ < div style = { { width : '100%' , height : '200px' , background : 'lightgreen' } } />
2007+ </ ObjectPageSection > ,
2008+ < ObjectPageSection
2009+ key = { 'customheader2' }
2010+ titleText = "Custom Header Section Two"
2011+ hideTitleText
2012+ id = "custom2"
2013+ header = { < MessageStrip hideCloseButton > Custom Header Section Two</ MessageStrip > }
2014+ >
2015+ < ObjectPageSubSection
2016+ titleText = "Subsection1"
2017+ id = "sub1"
2018+ actions = {
2019+ < >
2020+ < Button design = { ButtonDesign . Emphasized } style = { { minWidth : '120px' } } >
2021+ Custom Action
2022+ </ Button >
2023+ < Button design = { ButtonDesign . Transparent } icon = "action-settings" tooltip = "settings" />
2024+ < Button design = { ButtonDesign . Transparent } icon = "download" tooltip = "download" />
2025+ </ >
2026+ }
2027+ >
2028+ < div style = { { width : '100%' , height : '300px' , background : 'cadetblue' } } />
2029+ </ ObjectPageSubSection >
2030+ < ObjectPageSubSection titleText = "Subsection2" id = "sub2" >
2031+ < div style = { { width : '100%' , height : '300px' , background : 'cadetblue' } } />
2032+ </ ObjectPageSubSection >
2033+ </ ObjectPageSection > ,
2034+ ] ;
2035+
19552036const HeaderWithLargeForm = (
19562037 < ObjectPageHeader >
19572038 < Form layout = "S1 M2 L2 XL2" >
0 commit comments