Skip to content

Commit 068bb0e

Browse files
committed
fix(ObjectPage): fire onSelectedSectionChange correctly in IconTabBar mode
1 parent 3afa357 commit 068bb0e

File tree

2 files changed

+76
-15
lines changed

2 files changed

+76
-15
lines changed

packages/main/src/components/ObjectPage/ObjectPage.cy.tsx

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,31 +1284,75 @@ describe('ObjectPage', () => {
12841284
</>
12851285
);
12861286
};
1287-
1287+
const changeSpy = cy.spy().as('change');
1288+
let callCount = 1;
12881289
[{ titleArea: DPTitle, headerArea: DPContent }, { titleArea: DPTitle }, { headerArea: DPContent }, {}].forEach(
12891290
(props: ObjectPagePropTypes) => {
1290-
cy.mount(<TestComp {...props} mode={mode} selectedSubSectionId={`employment-job-relationship`} />);
1291+
cy.mount(
1292+
<TestComp
1293+
{...props}
1294+
mode={mode}
1295+
selectedSubSectionId={`employment-job-relationship`}
1296+
onSelectedSectionChange={changeSpy}
1297+
/>
1298+
);
12911299

12921300
cy.findByText('employment-job-relationship-content').should('be.visible');
12931301
cy.findByText('Job Information').should('not.be.visible');
12941302
cy.get('[ui5-tabcontainer]').findUi5TabByText('Employment').should('have.attr', 'aria-selected', 'true');
12951303

1296-
cy.mount(<TestComp {...props} selectedSectionId={`personal`} />);
1304+
cy.mount(
1305+
<TestComp {...props} mode={mode} selectedSectionId={`personal`} onSelectedSectionChange={changeSpy} />
1306+
);
12971307
cy.findByText('personal-connect-content').should('be.visible');
1298-
cy.findByText('test-content').should('not.be.visible');
1308+
1309+
if (mode === 'IconTabBar') {
1310+
cy.findByText('test-content').should('not.exist');
1311+
} else {
1312+
cy.findByText('test-content').should('not.be.visible');
1313+
}
12991314
cy.get('[ui5-tabcontainer]').findUi5TabByText('Personal').should('have.attr', 'aria-selected', 'true');
13001315

13011316
cy.wait(100);
13021317
cy.findByText('Select Goals').click();
13031318
cy.findByText('goals-content').should('be.visible');
1319+
cy.get('@change').should('have.callCount', callCount);
1320+
callCount++;
1321+
if (mode === 'IconTabBar') {
1322+
cy.findByText('personal-connect-content').should('not.exist');
1323+
} else {
1324+
cy.findByText('personal-connect-content').should('not.be.visible');
1325+
}
1326+
cy.get('[ui5-tabcontainer]').findUi5TabByText('Goals').should('have.attr', 'aria-selected', 'true');
13041327

1305-
cy.findByText('personal-connect-content').should('not.be.visible');
1328+
cy.get('[ui5-tabcontainer]').findUi5TabByText('Personal').click();
1329+
if (mode === 'IconTabBar') {
1330+
cy.findByText('test-content').should('not.exist');
1331+
} else {
1332+
cy.findByText('test-content').should('not.be.visible');
1333+
}
1334+
cy.findByText('personal-connect-content').should('be.visible');
1335+
cy.get('[ui5-tabcontainer]').findUi5TabByText('Personal').should('have.attr', 'aria-selected', 'true');
1336+
cy.get('@change').should('have.callCount', callCount);
1337+
callCount++;
1338+
1339+
cy.get('[ui5-tabcontainer]').findUi5TabByText('Goals').click();
1340+
if (mode === 'IconTabBar') {
1341+
cy.findByText('personal-connect-content').should('not.exist');
1342+
} else {
1343+
cy.findByText('personal-connect-content').should('not.be.visible');
1344+
}
1345+
cy.findByText('goals-content').should('be.visible');
13061346
cy.get('[ui5-tabcontainer]').findUi5TabByText('Goals').should('have.attr', 'aria-selected', 'true');
1347+
cy.get('@change').should('have.callCount', callCount);
1348+
callCount++;
13071349

13081350
cy.findByText('Select Payment Information').click();
13091351
cy.findByText('personal-payment-information-content').should('be.visible');
13101352
cy.findByText('personal-connect-content').should('not.be.visible');
13111353
cy.get('[ui5-tabcontainer]').findUi5TabByText('Personal').should('have.attr', 'aria-selected', 'true');
1354+
cy.get('@change').should('have.callCount', callCount);
1355+
callCount++;
13121356
}
13131357
);
13141358
});

packages/main/src/components/ObjectPage/index.tsx

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
debounce,
66
enrichEventWithDetails,
77
ThemingParameters,
8+
useIsomorphicLayoutEffect,
89
useStylesheet,
910
useSyncRef
1011
} from '@ui5/webcomponents-react-base';
@@ -108,6 +109,7 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
108109
const prevInternalSelectedSectionId = useRef(internalSelectedSectionId);
109110
const fireOnSelectedChangedEvent = (targetEvent, index, id, section) => {
110111
if (typeof onSelectedSectionChange === 'function' && targetEvent && prevInternalSelectedSectionId.current !== id) {
112+
console.log('FIRE!!!');
111113
onSelectedSectionChange(
112114
enrichEventWithDetails(targetEvent, {
113115
selectedSectionIndex: parseInt(index, 10),
@@ -249,18 +251,23 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
249251
fireOnSelectedChangedEvent(targetEvent, index, newSelectionSectionId, section);
250252
};
251253

252-
useEffect(() => {
254+
useIsomorphicLayoutEffect(() => {
253255
if (selectedSectionId) {
256+
const fireSelectEvent = () => {
257+
const selectedSection = getSectionElementById(objectPageRef.current, false, selectedSectionId);
258+
if (selectedSection) {
259+
const selectedSectionIndex = Array.from(
260+
selectedSection.parentElement.querySelectorAll(':scope > [data-component-name="ObjectPageSection"]')
261+
).indexOf(selectedSection);
262+
handleOnSectionSelected({}, selectedSectionId, selectedSectionIndex, selectedSection);
263+
}
264+
};
254265
if (mode === ObjectPageMode.IconTabBar) {
255266
setInternalSelectedSectionId(selectedSectionId);
256-
return;
257-
}
258-
const selectedSection = getSectionElementById(objectPageRef.current, false, selectedSectionId);
259-
if (selectedSection) {
260-
const selectedSectionIndex = Array.from(
261-
selectedSection.parentElement.querySelectorAll(':scope > [data-component-name="ObjectPageSection"]')
262-
).indexOf(selectedSection);
263-
handleOnSectionSelected({}, selectedSectionId, selectedSectionIndex, selectedSection);
267+
// In TabBar mode the section is only rendered when selected, therefore delay firing the event until the section is available in the DOM
268+
setTimeout(fireSelectEvent);
269+
} else {
270+
fireSelectEvent();
264271
}
265272
}
266273
}, [selectedSectionId, mode]);
@@ -300,6 +307,7 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
300307
}
301308
}, [headerPinned, topHeaderHeight]);
302309

310+
const isInitialTabBarMode = useRef(true);
303311
useEffect(() => {
304312
if (!isMounted) {
305313
requestAnimationFrame(() => setIsMounted(true));
@@ -311,24 +319,33 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
311319
isProgrammaticallyScrolled.current = true;
312320
if (mode === ObjectPageMode.IconTabBar) {
313321
let sectionId: string;
314-
childrenArray.forEach((section) => {
322+
let curSection: ReactElement;
323+
let sectionIndex: number = -1;
324+
childrenArray.forEach((section, index) => {
315325
if (isValidElement(section) && section.props && section.props.children) {
316326
safeGetChildrenArray(section.props.children).forEach((subSection) => {
317327
if (
318328
isValidElement(subSection) &&
319329
subSection.props &&
320330
(subSection as ReactElement<ObjectPageSubSectionPropTypes>).props.id === props.selectedSubSectionId
321331
) {
332+
curSection = section;
322333
sectionId = section.props?.id;
334+
sectionIndex = index;
323335
}
324336
});
325337
}
326338
});
327339
if (sectionId) {
340+
if (!isInitialTabBarMode.current) {
341+
//In TabBar mode the section is often not scrolled when subsection changes, thus the onSelectedSectionChange isn't fired
342+
debouncedOnSectionChange({}, sectionIndex, sectionId, curSection);
343+
}
328344
setInternalSelectedSectionId(sectionId);
329345
}
330346
}
331347
}
348+
isInitialTabBarMode.current = false;
332349
}, [props.selectedSubSectionId, isMounted]);
333350

334351
const tabContainerContainerRef = useRef(null);

0 commit comments

Comments
 (0)