Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accessibility tab order #4140

Merged
merged 11 commits into from
Feb 17, 2025
56 changes: 29 additions & 27 deletions core/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -1954,6 +1954,33 @@
</div>
</div>
{:else}
{#if !isHeaderDisabled}
<TopNav
hideSearchComponent={hideGlobalSearch}
pathData={navigationPath}
{pathParams}
on:handleClick={handleNavClick}
on:resizeTabNav={onResizeTabNav}
on:toggleSearch={toggleSearch}
on:closeSearchResult={closeSearchResult}
on:handleSearchNavigation={handleSearchNavigation}
bind:isSearchFieldVisible
bind:displaySearchResult
bind:searchResult
bind:inputElem
bind:customSearchItemRendererSlot
{burgerTooltip}
/>
{/if}
{#if !(hideNav || hideSideNav)}
<LeftNav
pathData={navigationPath}
{pathParams}
on:handleClick={handleNavClick}
on:resizeTabNav={onResizeTabNav}
{burgerTooltip}
/>
{/if}
<Backdrop disable={disableBackdrop}>
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<div
Expand Down Expand Up @@ -1992,39 +2019,14 @@
</div>
</div>
{/if}
{#if !isHeaderDisabled}
<TopNav
hideSearchComponent={hideGlobalSearch}
pathData={navigationPath}
{pathParams}
on:handleClick={handleNavClick}
on:resizeTabNav={onResizeTabNav}
on:toggleSearch={toggleSearch}
on:closeSearchResult={closeSearchResult}
on:handleSearchNavigation={handleSearchNavigation}
bind:isSearchFieldVisible
bind:displaySearchResult
bind:searchResult
bind:inputElem
bind:customSearchItemRendererSlot
{burgerTooltip}
/>
{/if}

{#if !hideNav}
<GlobalNav pathData={navigationPath} {pathParams} on:handleClick={handleNavClick} />
{#if breadcrumbsEnabled}
<Breadcrumb pathData={navigationPath} {pathParams} on:handleClick={handleNavClick} />
{/if}
{/if}
{#if !(hideNav || hideSideNav)}
<LeftNav
pathData={navigationPath}
{pathParams}
on:handleClick={handleNavClick}
on:resizeTabNav={onResizeTabNav}
{burgerTooltip}
/>
{/if}

{#if tabNav && !hideNav}
<TabNav pathData={navigationPath} {pathParams} on:handleClick={handleNavClick} {resizeTabNavToggle} />
{/if}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<title></title>
Expand Down Expand Up @@ -40,7 +40,7 @@
</style>
</head>

<body style="-webkit-font-smoothing: antialiased;">
<body style="-webkit-font-smoothing: antialiased">
<div id="routeCnt"></div>
<div id="imgCnt"></div>
<div id="textCnt">
Expand All @@ -63,6 +63,12 @@ <h1 id="title">Multi purpose demo page</h1>
>
Open <code>/home/one</code> as split view
</button>
<button class="addBackdrop" onclick="LuigiClient.uxManager().addBackdrop()">
add backdrop
</button>
<button class="removeBackdrop" onclick="LuigiClient.uxManager().removeBackdrop()">
remove backdrop
</button>
</div>

<script>
Expand Down Expand Up @@ -115,14 +121,14 @@ <h1 id="title">Multi purpose demo page</h1>
function vgDataUpdate() {
LuigiClient.setViewGroupData({
foo: 'Luigi rocks',
bar: '(' + Math.round(Math.random() * 100) + ')'
bar: '(' + Math.round(Math.random() * 100) + ')',
});
}
LuigiClient.addInitListener(updateFn);
LuigiClient.addContextUpdateListener(updateFn);

// fallback visibility if no initlistener called for 3 seconds
setTimeout(function() {
setTimeout(function () {
document.getElementById('textCnt').classList.add('visible');
}, 3000);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,11 @@ describe('JS-TEST-APP 4', () => {
cy.visitTestAppLoggedIn('/', newConfig);
cy.get('[data-testid="luigi-topnav-profile-btn"]').click();
cy.get('[data-testid="settings-link"]').should('exist');
cy.get('[data-testid="settings-link"]')
.contains('Settings')
.click();
cy.get('[data-testid="settings-link"]').contains('Settings').click();
cy.get('body').tab();
cy.tab();
cy.tab();
cy.get('.lui-us-navlist__item .fd-list__title')
.contains('Language & Region')
.focused()
.type('{enter}');
cy.get('.lui-us-navlist__item .fd-list__title').contains('Language & Region').focused().type('{enter}');
cy.tab();
cy.tab();
cy.get('[data-testid="lui-us-enum-0"]').click(); //workaround; Does not work with 'enter' or 'space'
Expand Down Expand Up @@ -155,37 +150,19 @@ describe('JS-TEST-APP 4', () => {
it('Left nav a11y', () => {
cy.visitTestApp('/home', newConfig);

cy.get('.fd-navigation.fd-navigation--vertical')
.contains('Section one')
.click();
cy.get('.fd-navigation__list-item.lui-nav-entry')
.contains('Node 1')
.should('not.be.visible');
cy.get('.fd-navigation.fd-navigation--vertical').contains('Section one').click();
cy.get('.fd-navigation__list-item.lui-nav-entry').contains('Node 1').should('not.be.visible');
cy.tab();
cy.tab();
cy.get('.fd-navigation__list-item.lui-nav-entry')
.contains('My Cat')
.should('be.focused');
cy.get('.fd-navigation__list-item.lui-nav-entry')
.contains('My Cat')
.focused()
.type('{enter}');
cy.get('.fd-navigation__list-item.lui-nav-entry')
.contains('Node 1')
.should('be.visible');
cy.get('.fd-navigation__list-item.lui-nav-entry').contains('My Cat').should('be.focused');
cy.get('.fd-navigation__list-item.lui-nav-entry').contains('My Cat').focused().type('{enter}');
cy.get('.fd-navigation__list-item.lui-nav-entry').contains('Node 1').should('be.visible');
cy.tab();
cy.get('.fd-navigation__list-item.lui-nav-entry')
.contains('Node 1')
.should('be.focused');
cy.get('.fd-navigation__list-item.lui-nav-entry')
.contains('Node 1')
.click();
cy.getIframeBody({}, 0, '.iframeContainer').then(result => {
cy.get('.fd-navigation__list-item.lui-nav-entry').contains('Node 1').should('be.focused');
cy.get('.fd-navigation__list-item.lui-nav-entry').contains('Node 1').click();
cy.getIframeBody({}, 0, '.iframeContainer').then((result) => {
$iframeBody = result;
cy.wrap($iframeBody)
.find('#content')
.contains('Content of node 1')
.should('be.visible');
cy.wrap($iframeBody).find('#content').contains('Content of node 1').should('be.visible');
});
});
it('More Btn in left nav', () => {
Expand All @@ -202,12 +179,41 @@ describe('JS-TEST-APP 4', () => {
cy.get('.lui-nav-more .fd-navigation__link').should('not.have.focus');
cy.tab();
cy.get('.lui-nav-more .fd-navigation__link').should('have.focus');
cy.get('.lui-nav-more .fd-navigation__link')
.focused()
.type('{enter}');
cy.get('.lui-nav-more .fd-navigation__link').focused().type('{enter}');
cy.get('.fd-navigation__list-container.fd-navigation__list-container--menu').should('be.visible');
cy.tab();
cy.get('.lui-moreItems .fd-navigation__list-item.lui-nav-entry .fd-navigation__link').should('have.focus');
});
});

describe('Shellbar logo gets focused first', () => {
let newConfig;
beforeEach(() => {
newConfig = structuredClone(defaultLuigiConfig);
newConfig.navigation.addNavHrefs = true;
});
it('Shellbar logo gets focused first', () => {
cy.visitTestApp('/home', newConfig);
cy.window().then((win) => {
win.focus();
});
cy.get('body').click();
cy.tab();
cy.get('.fd-shellbar__logo').should('have.focus');
});
it('Shellbar logo gets focused first with btpLayout', () => {
newConfig.settings.btpToolLayout = true;
newConfig.settings.experimental = {
btpToolLayout: true
};
cy.visitTestApp('/home', newConfig);
cy.window().then((win) => {
win.focus();
});
cy.get('body').click();
cy.tab();
cy.tab();
cy.get('.fd-shellbar__logo').should('have.focus');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,19 @@ describe('JS-TEST-APP with BTP layout', () => {
it('renders the split view separator and dragger with the correct width', () => {
cy.visitTestApp('/home', newConfig);
cy.get('#app[configversion="split-view"]');
cy.getIframeBody().then($iframeBody => {
cy.wrap($iframeBody)
.find('button.openSplitView')
.click();
cy.getIframeBody().then(($iframeBody) => {
cy.wrap($iframeBody).find('button.openSplitView').click();
});

cy.get('div.fd-page.iframeContainer')
.invoke('width')
.then(iframeContainerWidth => {
.then((iframeContainerWidth) => {
cy.get('div#splitViewContainer')
.invoke('width')
.then(splitViewContainerWidth => {
.then((splitViewContainerWidth) => {
cy.get('div#splitViewDragger')
.invoke('width')
.then(splitViewDraggerWidth => {
.then((splitViewDraggerWidth) => {
expect(iframeContainerWidth).to.equal(splitViewContainerWidth);
expect(iframeContainerWidth).to.equal(splitViewDraggerWidth);
});
Expand All @@ -43,4 +41,40 @@ describe('JS-TEST-APP with BTP layout', () => {
});
});
});

describe('addBackdrop, removeBackdrop btpLayout', () => {
let newConfig;
beforeEach(() => {
newConfig = structuredClone(defaultLuigiConfig);
newConfig.tag = 'addBackdrop';
});
it('addBackDrop, removeBackdrop', () => {
let $iframeBody;
cy.visitTestApp('/home/one', newConfig);
cy.get('#app[configversion="addBackdrop"]');
cy.get('.lui-backdrop').should('not.exist');
cy.getIframeBody({}, 0, '.iframeContainer').then((result) => {
$iframeBody = result;
cy.wrap($iframeBody).find('.addBackdrop').contains('add backdrop').click();
});
cy.get('.lui-backdrop').should('exist');
cy.get('[data-testid="home_home"]').then(($btn) => {
cy.get('.lui-backdrop').then(($overlay) => {
const btnRect = $btn[0].getBoundingClientRect();
const overlayRect = $overlay[0].getBoundingClientRect();

expect(overlayRect.top).to.be.at.most(btnRect.top);
expect(overlayRect.left).to.be.at.most(btnRect.left);
expect(overlayRect.bottom).to.be.at.least(btnRect.bottom);
expect(overlayRect.right).to.be.at.least(btnRect.right);
});
});

cy.getIframeBody({}, 0, '.iframeContainer').then((result) => {
$iframeBody = result;
cy.wrap($iframeBody).find('.removeBackdrop').contains('remove backdrop').click();
});
cy.get('.lui-backdrop').should('not.exist');
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import defaultLuigiConfig from '../../configs/default';

describe('addBackdrop, removeBackdrop', () => {
let newConfig;
beforeEach(() => {
newConfig = structuredClone(defaultLuigiConfig);
newConfig.tag = 'addBackdrop';
});
it('addBackDrop', () => {
let $iframeBody;
cy.visitTestApp('/home/one', newConfig);
cy.get('#app[configversion="addBackdrop"]');
cy.get('.lui-backdrop').should('not.exist');
cy.getIframeBody({}, 0, '.iframeContainer').then((result) => {
$iframeBody = result;
cy.wrap($iframeBody).find('.addBackdrop').contains('add backdrop').click();
});
cy.get('.lui-backdrop').should('exist');
cy.get('[data-testid="home_home"]').then(($btn) => {
cy.get('.lui-backdrop').then(($overlay) => {
const btnRect = $btn[0].getBoundingClientRect();
const overlayRect = $overlay[0].getBoundingClientRect();

expect(overlayRect.top).to.be.at.most(btnRect.top);
expect(overlayRect.left).to.be.at.most(btnRect.left);
expect(overlayRect.bottom).to.be.at.least(btnRect.bottom);
expect(overlayRect.right).to.be.at.least(btnRect.right);
});
});

cy.getIframeBody({}, 0, '.iframeContainer').then((result) => {
$iframeBody = result;
cy.wrap($iframeBody).find('.removeBackdrop').contains('remove backdrop').click();
});
cy.get('.lui-backdrop').should('not.exist');
});
});
Loading