mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 19:21:34 +08:00
@ -186,10 +186,20 @@ export class Loading implements ComponentInterface, OverlayInterface {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { message, spinner, htmlAttributes } = this;
|
const { message, spinner, htmlAttributes, overlayIndex } = this;
|
||||||
const mode = getIonMode(this);
|
const mode = getIonMode(this);
|
||||||
|
const msgId = `loading-${overlayIndex}-msg`;
|
||||||
|
/**
|
||||||
|
* If the message is defined, use that as the label.
|
||||||
|
* Otherwise, don't set aria-labelledby.
|
||||||
|
*/
|
||||||
|
const ariaLabelledBy = message !== undefined ? msgId : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Host
|
<Host
|
||||||
|
role="dialog"
|
||||||
|
aria-modal="true"
|
||||||
|
aria-labelledby={ariaLabelledBy}
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
{...(htmlAttributes as any)}
|
{...(htmlAttributes as any)}
|
||||||
style={{
|
style={{
|
||||||
@ -207,14 +217,16 @@ export class Loading implements ComponentInterface, OverlayInterface {
|
|||||||
|
|
||||||
<div tabindex="0"></div>
|
<div tabindex="0"></div>
|
||||||
|
|
||||||
<div class="loading-wrapper ion-overlay-wrapper" role="dialog">
|
<div class="loading-wrapper ion-overlay-wrapper">
|
||||||
{spinner && (
|
{spinner && (
|
||||||
<div class="loading-spinner">
|
<div class="loading-spinner">
|
||||||
<ion-spinner name={spinner} aria-hidden="true" />
|
<ion-spinner name={spinner} aria-hidden="true" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{message !== undefined && <div class="loading-content" innerHTML={sanitizeDOMString(message)}></div>}
|
{message !== undefined && (
|
||||||
|
<div class="loading-content" id={msgId} innerHTML={sanitizeDOMString(message)}></div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div tabindex="0"></div>
|
<div tabindex="0"></div>
|
||||||
|
50
core/src/components/loading/test/a11y/index.html
Normal file
50
core/src/components/loading/test/a11y/index.html
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" dir="ltr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>Loading - a11y</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
|
||||||
|
<link href="../../../../../css/core.css" rel="stylesheet" />
|
||||||
|
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
|
||||||
|
<script src="../../../../../scripts/testing/scripts.js"></script>
|
||||||
|
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
|
||||||
|
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||||
|
<script type="module">
|
||||||
|
import { loadingController } from '../../../../../dist/ionic/index.esm.js';
|
||||||
|
window.loadingController = loadingController;
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<main>
|
||||||
|
<h1>Loading - a11y</h1>
|
||||||
|
<button
|
||||||
|
id="open-message-loading"
|
||||||
|
onclick="openLoading({
|
||||||
|
message: 'Loading'
|
||||||
|
})"
|
||||||
|
>
|
||||||
|
Present Loading with Message
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
id="open-label-loading"
|
||||||
|
onclick="openLoading({
|
||||||
|
spinner: 'bubbles',
|
||||||
|
htmlAttributes: {
|
||||||
|
'aria-label': 'Loading'
|
||||||
|
}
|
||||||
|
})"
|
||||||
|
>
|
||||||
|
Present Loading with Label
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
async function openLoading(opts) {
|
||||||
|
const loading = await loadingController.create(opts);
|
||||||
|
await loading.present();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
34
core/src/components/loading/test/a11y/loading.e2e.ts
Normal file
34
core/src/components/loading/test/a11y/loading.e2e.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import AxeBuilder from '@axe-core/playwright';
|
||||||
|
import { expect } from '@playwright/test';
|
||||||
|
import { test } from '@utils/test/playwright';
|
||||||
|
|
||||||
|
test.describe('loading: a11y', () => {
|
||||||
|
test.beforeEach(({ skip }) => {
|
||||||
|
skip.mode('md');
|
||||||
|
skip.rtl();
|
||||||
|
});
|
||||||
|
test('should set aria-labelledby with a message', async ({ page }) => {
|
||||||
|
await page.goto('/src/components/loading/test/a11y');
|
||||||
|
|
||||||
|
const ionLoadingDidPresent = await page.spyOnEvent('ionLoadingDidPresent');
|
||||||
|
|
||||||
|
await page.click('#open-message-loading');
|
||||||
|
|
||||||
|
await ionLoadingDidPresent.next();
|
||||||
|
|
||||||
|
const results = await new AxeBuilder({ page }).analyze();
|
||||||
|
expect(results.violations).toEqual([]);
|
||||||
|
});
|
||||||
|
test('should set aria-labelledby with a label', async ({ page }) => {
|
||||||
|
await page.goto('/src/components/loading/test/a11y');
|
||||||
|
|
||||||
|
const ionLoadingDidPresent = await page.spyOnEvent('ionLoadingDidPresent');
|
||||||
|
|
||||||
|
await page.click('#open-label-loading');
|
||||||
|
|
||||||
|
await ionLoadingDidPresent.next();
|
||||||
|
|
||||||
|
const results = await new AxeBuilder({ page }).analyze();
|
||||||
|
expect(results.violations).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
Reference in New Issue
Block a user