Skip to content

Commit 251e20a

Browse files
authored
feat(ObjectPageSection): add tabRef prop (#7590)
Closes #7589 Related issue: #4369
1 parent b942f5f commit 251e20a

File tree

3 files changed

+54
-3
lines changed

3 files changed

+54
-3
lines changed

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

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import TitleLevel from '@ui5/webcomponents/dist/types/TitleLevel.js';
77
import ValueState from '@ui5/webcomponents-base/dist/types/ValueState.js';
88
import IllustrationMessageType from '@ui5/webcomponents-fiori/dist/types/IllustrationMessageType.js';
99
import type { CSSProperties } from 'react';
10-
import { useEffect, useReducer, useRef, useState } from 'react';
10+
import { useEffect, useLayoutEffect, useReducer, useRef, useState } from 'react';
1111
import type { ObjectPagePropTypes } from '../..';
1212
import {
1313
CheckBox,
@@ -45,6 +45,7 @@ import {
4545
ToolbarButton,
4646
} from '../..';
4747
import { cypressPassThroughTestsFactory } from '@/cypress/support/utils';
48+
import type { TabDomRef } from '../../webComponents/Tab/index.js';
4849

4950
const arbitraryCharsId = `~\`!1@#$%^&*()-_+={}[]:;"'z,<.>/?|♥`;
5051

@@ -1432,6 +1433,45 @@ describe('ObjectPage', () => {
14321433
cy.get('footer').should('have.attr', 'role', 'contentinfo');
14331434
});
14341435

1436+
it('tabRef', () => {
1437+
const TestComp = () => {
1438+
const tabRef = useRef(null);
1439+
1440+
useLayoutEffect(() => {
1441+
if (tabRef.current) {
1442+
requestAnimationFrame(() => {
1443+
tabRef.current.getDomRefInStrip().setAttribute('data-hello', 'true');
1444+
});
1445+
}
1446+
}, []);
1447+
1448+
return (
1449+
<ObjectPage>
1450+
<ObjectPageSection
1451+
id="0"
1452+
titleText="callbackRef"
1453+
tabRef={(node: TabDomRef | null) => {
1454+
if (node) {
1455+
requestAnimationFrame(() => {
1456+
node.getDomRefInStrip().setAttribute('data-hello', 'true');
1457+
});
1458+
}
1459+
}}
1460+
>
1461+
Content
1462+
</ObjectPageSection>
1463+
<ObjectPageSection id="1" titleText="refObject" tabRef={tabRef}>
1464+
Content
1465+
</ObjectPageSection>
1466+
</ObjectPage>
1467+
);
1468+
};
1469+
1470+
cy.mount(<TestComp />);
1471+
1472+
cy.get('[data-hello="true"]').should('be.visible').should('have.length', 2);
1473+
});
1474+
14351475
cypressPassThroughTestsFactory(ObjectPage);
14361476

14371477
it('focus behavior & keyboard navigation', () => {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,7 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
724724
return (
725725
<Tab
726726
key={`Anchor-${section.props?.id}`}
727+
ref={section.props.tabRef}
727728
data-index={index}
728729
data-section-id={section.props.id}
729730
text={section.props.titleText}

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
import type TitleLevel from '@ui5/webcomponents/dist/types/TitleLevel.js';
44
import { useStylesheet, useSyncRef } from '@ui5/webcomponents-react-base';
55
import { clsx } from 'clsx';
6-
import type { ReactNode, FocusEventHandler, KeyboardEventHandler, FocusEvent } from 'react';
6+
import type { ReactNode, FocusEventHandler, KeyboardEventHandler, FocusEvent, Ref } from 'react';
77
import { Children, isValidElement, forwardRef, useMemo } from 'react';
88
import { ObjectPageMode } from '../../enums/ObjectPageMode.js';
99
import type { CommonProps } from '../../types/index.js';
10+
import type { TabDomRef } from '../../webComponents/Tab/index.js';
1011
import { useObjectPageContext } from '../ObjectPage/context.js';
1112
import { navigateSections } from '../ObjectPage/ObjectPageUtils.js';
1213
import { classNames, styleData } from './ObjectPageSection.module.css.js';
@@ -57,6 +58,12 @@ export interface ObjectPageSectionPropTypes extends CommonProps {
5758
* __Note__: Although this prop accepts all HTML Elements, it is strongly recommended that you only use non-focusable elements to preserve the intended design.
5859
*/
5960
header?: ReactNode;
61+
// the ref is applied in the ObjectPage
62+
/**
63+
* This ref will be attached to the underlying `ui5-tab` DOM element,
64+
* allowing direct access to its instance methods and properties (e.g. `getDomRefInStrip`).
65+
*/
66+
tabRef?: Ref<TabDomRef>;
6067
}
6168

6269
function recursiveSetTabIndexOnSubSection(el: HTMLElement | null, currentTarget: HTMLElement): void {
@@ -121,6 +128,9 @@ const ObjectPageSection = forwardRef<HTMLElement, ObjectPageSectionPropTypes>((p
121128
header,
122129
...rest
123130
} = props;
131+
132+
const { tabRef: _0, ...propsWithoutOmitted } = rest;
133+
124134
useStylesheet(styleData, ObjectPageSection.displayName);
125135
const [componentRef, sectionRef] = useSyncRef(ref);
126136
const htmlId = `ObjectPageSection-${id}`;
@@ -227,7 +237,7 @@ const ObjectPageSection = forwardRef<HTMLElement, ObjectPageSectionPropTypes>((p
227237
className={clsx(classNames.section, wrapTitleText && classNames.wrap, className)}
228238
style={style}
229239
tabIndex={objectPageMode === ObjectPageMode.Default ? -1 : 0}
230-
{...rest}
240+
{...propsWithoutOmitted}
231241
id={htmlId}
232242
data-component-name="ObjectPageSection"
233243
onFocus={objectPageMode === ObjectPageMode.Default ? handleFocusDefault : handleFocusIconTabBar}

0 commit comments

Comments
 (0)