chore(aria): add separate setup function for polyfill and focusability

PiperOrigin-RevId: 576973090
This commit is contained in:
Elizabeth Mitchell 2023-10-26 13:36:41 -07:00 committed by Copybara-Service
parent e7bc633e18
commit f94de5d302
2 changed files with 40 additions and 66 deletions

View File

@ -294,6 +294,27 @@ export type ARIARole =
| 'doc-tip'
| 'doc-toc';
/**
* This function will polyfill `ARIAMixin` properties for Firefox.
*
* @param ctor The `ReactiveElement` constructor to set up.
*/
export function polyfillARIAMixin(ctor: typeof ReactiveElement) {
if (isServer || 'role' in Element.prototype) {
return;
}
// Polyfill reflective aria properties for Firefox
for (const ariaProperty of ARIA_PROPERTIES) {
ctor.createProperty(ariaProperty, {
attribute: ariaPropertyToAttribute(ariaProperty),
reflect: true,
});
}
ctor.createProperty('role', {reflect: true});
}
/**
* Enables a host custom element to be the target for aria roles and attributes.
* Components should set the `elementInternals.role` property.
@ -307,6 +328,8 @@ export type ARIARole =
*
* @param ctor The `ReactiveElement` constructor to set up.
* @param options Options to configure the element's host aria.
* @deprecated use `mixinFocusable()` and `polyfillARIAMixin()`
* TODO(b/307785469): remove after updating components to use mixinFocusable
*/
export function setupHostAria(
ctor: typeof ReactiveElement,
@ -326,23 +349,13 @@ export function setupHostAria(
});
}
if (isServer || 'role' in Element.prototype) {
return;
}
// Polyfill reflective aria properties for Firefox
for (const ariaProperty of ARIA_PROPERTIES) {
ctor.createProperty(ariaProperty, {
attribute: ariaPropertyToAttribute(ariaProperty),
reflect: true,
});
}
ctor.createProperty('role', {reflect: true});
polyfillARIAMixin(ctor);
}
/**
* Options for setting up a host element as an aria target.
* @deprecated use `mixinFocusable()` and `polyfillARIAMixin()`
* TODO(b/307785469): remove after updating components to use mixinFocusable
*/
export interface SetupHostAriaOptions {
/**

View File

@ -13,8 +13,8 @@ import {
ARIAProperty,
ariaPropertyToAttribute,
isAriaAttribute,
polyfillARIAMixin,
polyfillElementInternalsAria,
setupHostAria,
} from './aria.js';
describe('aria', () => {
@ -52,11 +52,11 @@ describe('aria', () => {
});
});
describe('setupHostAria()', () => {
describe('polyfillARIAMixin()', () => {
@customElement('test-setup-aria-host')
class TestElement extends LitElement {
static {
setupHostAria(TestElement);
polyfillARIAMixin(TestElement);
}
override render() {
@ -64,67 +64,28 @@ describe('aria', () => {
}
}
it('should not hydrate tabindex attribute on creation', () => {
const element = new TestElement();
expect(element.hasAttribute('tabindex'))
.withContext('has tabindex attribute')
.toBeFalse();
});
it('should set tabindex="0" on element once connected', () => {
it('should reflect ARIAMixin properties to attributes', async () => {
const element = new TestElement();
document.body.appendChild(element);
expect(element.getAttribute('tabindex'))
.withContext('tabindex attribute value')
.toEqual('0');
element.role = 'button';
element.ariaLabel = 'Foo';
await element.updateComplete;
expect(element.getAttribute('role'))
.withContext('role attribute value')
.toEqual('button');
expect(element.getAttribute('aria-label'))
.withContext('aria-label attribute value')
.toEqual('Foo');
element.remove();
});
it('should not set tabindex on connected if one already exists', () => {
const element = new TestElement();
element.tabIndex = -1;
document.body.appendChild(element);
expect(element.getAttribute('tabindex'))
.withContext('tabindex attribute value')
.toEqual('-1');
element.remove();
});
it('should not change tabindex if disconnected and reconnected', () => {
const element = new TestElement();
document.body.appendChild(element);
element.tabIndex = -1;
element.remove();
document.body.appendChild(element);
expect(element.getAttribute('tabindex'))
.withContext('tabindex attribute value')
.toEqual('-1');
});
if (!('role' in Element.prototype)) {
describe('polyfill', () => {
it('should hydrate aria attributes when ARIAMixin is not supported', async () => {
const element = new TestElement();
document.body.appendChild(element);
element.role = 'button';
await element.updateComplete;
expect(element.getAttribute('role'))
.withContext('role attribute value')
.toEqual('button');
element.remove();
});
});
}
});
describe('polyfillElementInternalsAria()', () => {
@customElement('test-polyfill-element-internals-aria')
class TestElement extends LitElement {
static {
setupHostAria(TestElement);
polyfillARIAMixin(TestElement);
}
internals = polyfillElementInternalsAria(this, this.attachInternals());