fix(overlays): role preservation + guarded attr storage

This commit is contained in:
Thijs Louisse 2020-07-10 14:56:15 +02:00
parent 5b9f039457
commit c3f7aa8ea2
2 changed files with 38 additions and 9 deletions

View file

@ -67,8 +67,7 @@ const supportsCSSTypedObject = window.CSS && CSS.number;
* Note that a contentWrapperNode should be provided for [l2], [l3] and [l4] * Note that a contentWrapperNode should be provided for [l2], [l3] and [l4]
* In case of a global overlay ([g1]), it's enough to provide just the contentNode. * In case of a global overlay ([g1]), it's enough to provide just the contentNode.
* In case of a local overlay or a responsive overlay switching from placementMode, one should * In case of a local overlay or a responsive overlay switching from placementMode, one should
* always configure as if it was a local overlay. * always configure as if it were a local overlay.
*
*/ */
export class OverlayController { export class OverlayController {
@ -358,11 +357,14 @@ export class OverlayController {
__setupTeardownAccessibility({ phase }) { __setupTeardownAccessibility({ phase }) {
if (phase === 'init') { if (phase === 'init') {
this.__storeOriginalAttrs(this.contentNode, ['role', 'id']); this.__storeOriginalAttrs(this.contentNode, ['role', 'id']);
this.__storeOriginalAttrs(this.invokerNode, [
'aria-expanded', if (this.invokerNode) {
'aria-labelledby', this.__storeOriginalAttrs(this.invokerNode, [
'aria-describedby', 'aria-expanded',
]); 'aria-labelledby',
'aria-describedby',
]);
}
if (!this.contentNode.id) { if (!this.contentNode.id) {
this.contentNode.setAttribute('id', this._contentId); this.contentNode.setAttribute('id', this._contentId);
@ -379,7 +381,7 @@ export class OverlayController {
if (this.invokerNode) { if (this.invokerNode) {
this.invokerNode.setAttribute('aria-expanded', this.isShown); this.invokerNode.setAttribute('aria-expanded', this.isShown);
} }
if (!this.contentNode.role) { if (!this.contentNode.getAttribute('role')) {
this.contentNode.setAttribute('role', 'dialog'); this.contentNode.setAttribute('role', 'dialog');
} }
} }

View file

@ -68,7 +68,7 @@ describe('OverlayController', () => {
} }
if (mode === 'inline') { if (mode === 'inline') {
contentNode = await fixture(html` contentNode = await fixture(html`
<div style="z-index: ${zIndexVal} ;"> <div style="z-index: xxxxxxxxxxxx ;">
I should be on top I should be on top
</div> </div>
`); `);
@ -1113,6 +1113,33 @@ describe('OverlayController', () => {
expect(ctrl.contentNode.getAttribute('role')).to.equal('dialog'); expect(ctrl.contentNode.getAttribute('role')).to.equal('dialog');
}); });
it('preserves [role] on content when present', async () => {
const invokerNode = await fixture('<div role="button">invoker</div>');
const contentNode = await fixture('<div role="menu">invoker</div>');
const ctrl = new OverlayController({
...withLocalTestConfig(),
handlesAccessibility: true,
invokerNode,
contentNode,
});
expect(ctrl.contentNode.getAttribute('role')).to.equal('menu');
});
it('allows to not provide an invokerNode', async () => {
let properlyInstantiated = false;
try {
new OverlayController({
...withLocalTestConfig(),
handlesAccessibility: true,
invokerNode: null,
});
properlyInstantiated = true;
} catch (e) {
throw new Error(e);
}
expect(properlyInstantiated).to.be.true;
});
it('adds attributes inert and aria-hidden="true" on all siblings of rootNode if an overlay is shown', async () => { it('adds attributes inert and aria-hidden="true" on all siblings of rootNode if an overlay is shown', async () => {
const ctrl = new OverlayController({ const ctrl = new OverlayController({
...withGlobalTestConfig(), ...withGlobalTestConfig(),