Skip to content

Commit 118ea4a

Browse files
committed
fix(ObjectPage): handle scrollPaddingBlock when relatedTarget is null
1 parent e3b2f20 commit 118ea4a

File tree

3 files changed

+80
-4
lines changed

3 files changed

+80
-4
lines changed

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

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,14 @@ import {
4343
Title,
4444
Toolbar,
4545
ToolbarButton,
46+
Table,
47+
TableCell,
48+
TableHeaderCell,
49+
TableHeaderRow,
50+
TableRow,
4651
} from '../..';
47-
import { cypressPassThroughTestsFactory } from '@/cypress/support/utils';
4852
import type { TabDomRef } from '../../webComponents/Tab/index.js';
53+
import { cypressPassThroughTestsFactory } from '@/cypress/support/utils';
4954

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

@@ -1651,6 +1656,22 @@ describe('ObjectPage', () => {
16511656
<Input data-testid="sub" />
16521657
</ObjectPageSubSection>
16531658
</ObjectPageSection>
1659+
<ObjectPageSection id={'7'} titleText={'Table'} aria-label="Table">
1660+
<Table data-testid="table">
1661+
<TableHeaderRow slot="headerRow">
1662+
<TableHeaderCell>Product</TableHeaderCell>
1663+
<TableHeaderCell>Supplier</TableHeaderCell>
1664+
<TableHeaderCell horizontalAlign="End">Price</TableHeaderCell>
1665+
</TableHeaderRow>
1666+
{new Array(20).fill(1337).map((_, i) => (
1667+
<TableRow key={i}>
1668+
<TableCell>Mac</TableCell>
1669+
<TableCell>Apple</TableCell>
1670+
<TableCell horizontalAlign="End">10.09</TableCell>
1671+
</TableRow>
1672+
))}
1673+
</Table>
1674+
</ObjectPageSection>
16541675
</ObjectPage>
16551676
</>,
16561677
);
@@ -1691,9 +1712,18 @@ describe('ObjectPage', () => {
16911712
// 6.2 input
16921713
cy.realPress('Tab');
16931714
cy.findByTestId('sub').should('be.focused');
1715+
// Table
1716+
cy.realPress('Tab');
1717+
cy.focused().should('have.attr', 'ui5-table-row');
16941718
//footer
16951719
cy.realPress('Tab');
16961720
cy.findByTestId('footer-accept-btn').should('be.focused');
1721+
// Table
1722+
cy.realPress(['Shift', 'Tab']);
1723+
cy.focused().should('have.attr', 'ui5-table-row');
1724+
// Table Section
1725+
cy.realPress(['Shift', 'Tab']);
1726+
cy.focused().should('have.attr', 'aria-label', 'Table').and('have.attr', 'tabindex', 0);
16971727
// 6.2 input
16981728
cy.realPress(['Shift', 'Tab']);
16991729
cy.findByTestId('sub').should('be.focused');
@@ -1730,10 +1760,12 @@ describe('ObjectPage', () => {
17301760
cy.get('[data-component-name="ObjectPageSubSection"]').should('have.attr', 'tabindex', -1);
17311761

17321762
// click first Tab
1763+
cy.log('click first Tab');
17331764
cy.focused().realClick();
17341765
cy.focused().should('have.attr', 'aria-label', 'Goals').and('have.attr', 'tabindex', 0);
17351766

17361767
// arrow section navigation
1768+
cy.log('arrow section navigation');
17371769
cy.realPress('ArrowUp');
17381770
cy.focused().should('have.attr', 'aria-label', 'Goals').and('have.attr', 'tabindex', 0);
17391771
cy.realPress('ArrowDown');
@@ -1747,9 +1779,25 @@ describe('ObjectPage', () => {
17471779
cy.realPress('ArrowDown');
17481780
cy.focused().should('have.attr', 'aria-label', 'SubSectionsInput').and('have.attr', 'tabindex', 0);
17491781
cy.realPress('ArrowDown');
1750-
cy.focused().should('have.attr', 'aria-label', 'SubSectionsInput').and('have.attr', 'tabindex', 0);
1782+
cy.focused()
1783+
.should('have.attr', 'aria-label', 'Table')
1784+
.and('have.attr', 'tabindex', 0)
1785+
.then(($el) => {
1786+
const rect = $el[0].getBoundingClientRect();
1787+
expect(rect.top).to.be.at.most(214);
1788+
});
1789+
cy.realPress('ArrowDown');
1790+
cy.focused()
1791+
.should('have.attr', 'aria-label', 'Table')
1792+
.and('have.attr', 'tabindex', 0)
1793+
.then(($el) => {
1794+
const rect = $el[0].getBoundingClientRect();
1795+
expect(rect.top).to.be.at.most(211);
1796+
});
17511797

17521798
// arrow subsection navigation
1799+
cy.log('arrow subsection navigation');
1800+
cy.realPress('ArrowUp');
17531801
cy.realPress('Tab');
17541802
cy.focused().should('have.attr', 'aria-label', '6.1').and('have.attr', 'tabindex', 0);
17551803
cy.realPress('ArrowUp');
@@ -1777,6 +1825,19 @@ describe('ObjectPage', () => {
17771825
cy.wrap(section).should('have.attr', 'tabindex', -1);
17781826
}
17791827
});
1828+
1829+
//Table row navigation (relatedTarget not present - scroll-padding fallback)
1830+
cy.log('Table row navigation');
1831+
cy.get('[ui5-tabcontainer]').findUi5TabByText('Table').click();
1832+
cy.realPress('Tab');
1833+
for (let i = 0; i < 15; i++) {
1834+
cy.realPress('ArrowDown');
1835+
}
1836+
cy.focused().should('be.visible').and('have.attr', 'ui5-table-row');
1837+
for (let i = 0; i < 13; i++) {
1838+
cy.realPress('ArrowUp');
1839+
}
1840+
cy.focused().should('be.visible').and('have.attr', 'ui5-table-row');
17801841
});
17811842
});
17821843

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
149149
scrollTimeout,
150150
},
151151
);
152+
const scrollPaddingBlock = `${Math.ceil(12 + topHeaderHeight + TAB_CONTAINER_HEADER_HEIGHT + (!headerCollapsed && headerPinned ? headerContentHeight : 0))}px ${footerArea ? 'calc(var(--_ui5wcr-BarHeight) + 1.25rem)' : 0}`;
152153

153154
useEffect(() => {
154155
if (typeof onToggleHeaderArea === 'function' && isToggledRef.current) {
@@ -780,13 +781,25 @@ const ObjectPage = forwardRef<ObjectPageDomRef, ObjectPagePropTypes>((props, ref
780781
const opNode = objectPageRef.current;
781782
if (opNode) {
782783
// 12px or 0.75rem margin for ui5wc border and input margins
783-
opNode.style.scrollPaddingBlock = `${Math.ceil(12 + topHeaderHeight + TAB_CONTAINER_HEADER_HEIGHT + (!headerCollapsed && headerPinned ? headerContentHeight : 0))}px ${footerArea ? 'calc(var(--_ui5wcr-BarHeight) + 1.25rem)' : 0}`;
784+
opNode.style.scrollPaddingBlock = scrollPaddingBlock;
784785
}
785786
}}
786787
onBlur={(e) => {
787788
const opNode = objectPageRef.current;
788-
if (opNode && !e.currentTarget.contains(e.relatedTarget as Node)) {
789+
if (!opNode) return;
790+
791+
if (e.relatedTarget && !e.currentTarget.contains(e.relatedTarget as Node)) {
792+
opNode.style.scrollPaddingBlock = '0px';
793+
// Fallback: Some (ui5-table) ui5wc components don't implement `relatedTarget` as expected.
794+
} else if (!e.relatedTarget) {
795+
const currentTarget = e.currentTarget;
789796
opNode.style.scrollPaddingBlock = '0px';
797+
requestAnimationFrame(() => {
798+
if (currentTarget.contains(document.activeElement)) {
799+
opNode.style.scrollPaddingBlock = scrollPaddingBlock;
800+
document.activeElement.scrollIntoView({ block: 'nearest' });
801+
}
802+
});
790803
}
791804
}}
792805
>

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ const ObjectPageSection = forwardRef<HTMLElement, ObjectPageSectionPropTypes>((p
201201
navigateSections({ e, onKeyDown: props.onKeyDown, componentName: 'ObjectPageSection' });
202202
const target = e.currentTarget as HTMLElement;
203203
if (
204+
target === e.target &&
204205
(e.key === 'ArrowDown' || e.key === 'ArrowRight') &&
205206
(target.nextElementSibling as HTMLElement).dataset.componentName === 'ObjectPageSection'
206207
) {
@@ -219,6 +220,7 @@ const ObjectPageSection = forwardRef<HTMLElement, ObjectPageSectionPropTypes>((p
219220
});
220221
}
221222
if (
223+
target === e.target &&
222224
(e.key === 'ArrowUp' || e.key === 'ArrowLeft') &&
223225
(target.previousElementSibling as HTMLElement).dataset.componentName === 'ObjectPageSection'
224226
) {

0 commit comments

Comments
 (0)