a11y: exported widget ARIA (slider/tabs/gallery)
ContentSlider, Tabs, and Gallery toHtml exports and their inline scripts now carry ARIA semantics and keyboard support: - ContentSlider: prev/next arrows and dot buttons get aria-labels, the slide stack is wrapped in an aria-live="polite" region, and the decorative chevron icons are aria-hidden. - Tabs: tablist/tab/tabpanel roles, aria-selected/aria-controls/ aria-labelledby, and Left/Right/Home/End arrow-key navigation in the inline script. The tab<->panel id scope is now derived from a deterministic hash of anchorId/labels instead of Math.random, since the ARIA linking ids must be stable across export runs. - Gallery: the lightbox overlay gets role="dialog"/aria-modal/aria-label, Escape closes it, and thumbnails are keyboard-operable (role="button" tabindex="0" plus Enter/Space handling in the existing delegated listener). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { ContentSlider } from './ContentSlider';
|
||||
|
||||
const toHtml = (ContentSlider as any).toHtml;
|
||||
|
||||
const slides = [
|
||||
{ type: 'image' as const, heading: 'One' },
|
||||
{ type: 'image' as const, heading: 'Two' },
|
||||
{ type: 'image' as const, heading: 'Three' },
|
||||
];
|
||||
|
||||
describe('ContentSlider.toHtml accessibility (F1.1)', () => {
|
||||
test('prev/next arrows get aria-labels and are real buttons', () => {
|
||||
const { html } = toHtml({ slides, showArrows: true }, '');
|
||||
expect(html).toMatch(/<button[^>]*aria-label="Previous slide"/);
|
||||
expect(html).toMatch(/<button[^>]*aria-label="Next slide"/);
|
||||
});
|
||||
|
||||
test('dot buttons get "Go to slide N" aria-labels', () => {
|
||||
const { html } = toHtml({ slides, showDots: true }, '');
|
||||
expect(html).toMatch(/<button[^>]*aria-label="Go to slide 1"/);
|
||||
expect(html).toMatch(/<button[^>]*aria-label="Go to slide 2"/);
|
||||
expect(html).toMatch(/<button[^>]*aria-label="Go to slide 3"/);
|
||||
});
|
||||
|
||||
test('slides are wrapped in an aria-live="polite" region', () => {
|
||||
const { html } = toHtml({ slides }, '');
|
||||
expect(html).toContain('aria-live="polite"');
|
||||
});
|
||||
|
||||
test('decorative chevron icons in arrows are aria-hidden', () => {
|
||||
const { html } = toHtml({ slides, showArrows: true }, '');
|
||||
expect(html).toMatch(/<i class="fa fa-chevron-left" aria-hidden="true"><\/i>/);
|
||||
expect(html).toMatch(/<i class="fa fa-chevron-right" aria-hidden="true"><\/i>/);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user