mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Emit pane aria-controls only while the pane is mounted
This commit is contained in:
@@ -56,6 +56,18 @@ describe('PaneToggleStrip', () => {
|
|||||||
expect(library.getAttribute('aria-label')).toBe('Library pane');
|
expect(library.getAttribute('aria-label')).toBe('Library pane');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('aria-controls points at the pane only while it is shown (no dangling IDREF)', () => {
|
||||||
|
// App unmounts a hidden pane's <section>, so emitting aria-controls then would
|
||||||
|
// leave the IDREF pointing at nothing. It must appear only when pressed/shown.
|
||||||
|
const [library] = toggleButtons();
|
||||||
|
expect(library.hasAttribute('aria-controls')).toBe(true);
|
||||||
|
|
||||||
|
act(() => library.click()); // hide the pane
|
||||||
|
|
||||||
|
expect(library.getAttribute('aria-pressed')).toBe('false');
|
||||||
|
expect(library.hasAttribute('aria-controls')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
test('roving tabindex: exactly one control is in the tab order at a time', () => {
|
test('roving tabindex: exactly one control is in the tab order at a time', () => {
|
||||||
const all = [...toggleButtons(), datasetsButton()];
|
const all = [...toggleButtons(), datasetsButton()];
|
||||||
expect(all.filter((b) => b.tabIndex === 0)).toHaveLength(1);
|
expect(all.filter((b) => b.tabIndex === 0)).toHaveLength(1);
|
||||||
|
|||||||
@@ -102,11 +102,13 @@ export function PaneToggleStrip() {
|
|||||||
type="button"
|
type="button"
|
||||||
aria-pressed={visible[item.pane]}
|
aria-pressed={visible[item.pane]}
|
||||||
aria-label={item.label}
|
aria-label={item.label}
|
||||||
// TODO: when a pane is hidden, App unmounts its <section>, so this
|
// Only point at the pane while it's actually mounted: App unmounts a
|
||||||
// aria-controls IDREF dangles until the pane is shown again. Harmless
|
// hidden pane's <section>, so emitting aria-controls then would leave a
|
||||||
// (AT ignores unresolved IDREFs) but technically invalid — consider
|
// dangling IDREF (invalid, even if AT ignores it). The association is
|
||||||
// keeping the section mounted-but-hidden, or dropping aria-controls.
|
// meaningful only when the target exists, and the aria-pressed state
|
||||||
aria-controls={item.controls}
|
// already conveys hidden/shown either way (contract: arch/10 → toggle
|
||||||
|
// strip — the bullet lists aria-pressed + a stable name, not controls).
|
||||||
|
aria-controls={visible[item.pane] ? item.controls : undefined}
|
||||||
// Description (not the name): hints what activating does. The name stays
|
// Description (not the name): hints what activating does. The name stays
|
||||||
// stable (aria-label) per APG's toggle-button rule.
|
// stable (aria-label) per APG's toggle-button rule.
|
||||||
title={`${visible[item.pane] ? 'Hide' : 'Show'} ${item.label.toLowerCase()}`}
|
title={`${visible[item.pane] ? 'Hide' : 'Show'} ${item.label.toLowerCase()}`}
|
||||||
|
|||||||
Reference in New Issue
Block a user