mirror of
https://github.com/material-components/material-web.git
synced 2024-08-17 01:20:23 +03:00
refactor: remove Firefox ARIAMixin polyfills (v119+)
This is now fixed in the latest two versions of Firefox https://bugzilla.mozilla.org/show_bug.cgi?id=1785412 PiperOrigin-RevId: 586442947
This commit is contained in:
parent
4c479299b1
commit
c319236cd1
@ -7,21 +7,12 @@
|
||||
import {html, isServer, LitElement} from 'lit';
|
||||
import {queryAssignedElements} from 'lit/decorators.js';
|
||||
|
||||
import {
|
||||
polyfillARIAMixin,
|
||||
polyfillElementInternalsAria,
|
||||
} from '../../internal/aria/aria.js';
|
||||
|
||||
import {Chip} from './chip.js';
|
||||
|
||||
/**
|
||||
* A chip set component.
|
||||
*/
|
||||
export class ChipSet extends LitElement {
|
||||
static {
|
||||
polyfillARIAMixin(ChipSet);
|
||||
}
|
||||
|
||||
get chips() {
|
||||
return this.childElements.filter(
|
||||
(child): child is Chip => child instanceof Chip,
|
||||
@ -29,11 +20,9 @@ export class ChipSet extends LitElement {
|
||||
}
|
||||
|
||||
@queryAssignedElements() private readonly childElements!: HTMLElement[];
|
||||
private readonly internals = polyfillElementInternalsAria(
|
||||
this,
|
||||
private readonly internals =
|
||||
// Cast needed for closure
|
||||
(this as HTMLElement).attachInternals(),
|
||||
);
|
||||
(this as HTMLElement).attachInternals();
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
@ -28,7 +28,7 @@ Browser | Version
|
||||
------- | -------
|
||||
Chrome | 112 +
|
||||
Edge | 112 +
|
||||
Firefox | 113 +
|
||||
Firefox | 119 +
|
||||
Safari* | 16.4 +
|
||||
|
||||
*\* previous versions of Safari may be supported with an
|
||||
|
@ -4,8 +4,6 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import {isServer, ReactiveElement} from 'lit';
|
||||
|
||||
/**
|
||||
* Accessibility Object Model reflective aria property name types.
|
||||
*/
|
||||
@ -293,172 +291,3 @@ export type ARIARole =
|
||||
| 'doc-subtitle'
|
||||
| '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});
|
||||
}
|
||||
|
||||
/**
|
||||
* Polyfills an element and its `ElementInternals` to support `ARIAMixin`
|
||||
* properties on internals. This is needed for Firefox.
|
||||
*
|
||||
* `polyfillARIAMixin()` must be called for the element class.
|
||||
*
|
||||
* @example
|
||||
* class XButton extends LitElement {
|
||||
* static {
|
||||
* polyfillARIAMixin(XButton);
|
||||
* }
|
||||
*
|
||||
* private internals =
|
||||
* polyfillElementInternalsAria(this, this.attachInternals());
|
||||
*
|
||||
* constructor() {
|
||||
* super();
|
||||
* this.internals.role = 'button';
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
export function polyfillElementInternalsAria(
|
||||
host: ReactiveElement,
|
||||
internals: ElementInternals,
|
||||
) {
|
||||
if (checkIfElementInternalsSupportsAria(internals)) {
|
||||
return internals;
|
||||
}
|
||||
|
||||
if (!('role' in host)) {
|
||||
throw new Error('Missing polyfillARIAMixin()');
|
||||
}
|
||||
|
||||
let firstConnectedCallbacks: Array<{
|
||||
property: ARIAProperty | 'role';
|
||||
callback: () => void;
|
||||
}> = [];
|
||||
let hasBeenConnected = false;
|
||||
|
||||
// Add support for Firefox, which has not yet implement ElementInternals aria
|
||||
for (const ariaProperty of ARIA_PROPERTIES) {
|
||||
let internalAriaValue: string | null = null;
|
||||
Object.defineProperty(internals, ariaProperty, {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get() {
|
||||
return internalAriaValue;
|
||||
},
|
||||
set(value: string | null) {
|
||||
const setValue = () => {
|
||||
internalAriaValue = value;
|
||||
if (!hasBeenConnected) {
|
||||
firstConnectedCallbacks.push({
|
||||
property: ariaProperty,
|
||||
callback: setValue,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Dynamic lookup rather than hardcoding all properties.
|
||||
// tslint:disable-next-line:no-dict-access-on-struct-type
|
||||
host[ariaProperty] = value;
|
||||
};
|
||||
|
||||
setValue();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
let internalRoleValue: string | null = null;
|
||||
Object.defineProperty(internals, 'role', {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get() {
|
||||
return internalRoleValue;
|
||||
},
|
||||
set(value: string | null) {
|
||||
const setRole = () => {
|
||||
internalRoleValue = value;
|
||||
|
||||
if (!hasBeenConnected) {
|
||||
firstConnectedCallbacks.push({
|
||||
property: 'role',
|
||||
callback: setRole,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (value === null) {
|
||||
host.removeAttribute('role');
|
||||
} else {
|
||||
host.setAttribute('role', value);
|
||||
}
|
||||
};
|
||||
|
||||
setRole();
|
||||
},
|
||||
});
|
||||
|
||||
host.addController({
|
||||
hostConnected() {
|
||||
if (hasBeenConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
hasBeenConnected = true;
|
||||
|
||||
const propertiesSetByUser = new Set<ARIAProperty | 'role'>();
|
||||
|
||||
// See which properties were set by the user on host before we apply
|
||||
// internals values as attributes to host. Needs to be done in another
|
||||
// for loop because the callbacks set these attributes on host.
|
||||
for (const {property} of firstConnectedCallbacks) {
|
||||
const wasSetByUser =
|
||||
host.getAttribute(ariaPropertyToAttribute(property)) !== null ||
|
||||
// Dynamic lookup rather than hardcoding all properties.
|
||||
// tslint:disable-next-line:no-dict-access-on-struct-type
|
||||
host[property] !== undefined;
|
||||
|
||||
if (wasSetByUser) {
|
||||
propertiesSetByUser.add(property);
|
||||
}
|
||||
}
|
||||
|
||||
for (const {property, callback} of firstConnectedCallbacks) {
|
||||
// If the user has set the attribute or property, do not override the
|
||||
// user's value
|
||||
if (propertiesSetByUser.has(property)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
callback();
|
||||
}
|
||||
|
||||
// Remove strong callback references
|
||||
firstConnectedCallbacks = [];
|
||||
},
|
||||
});
|
||||
|
||||
return internals;
|
||||
}
|
||||
|
||||
// Separate function so that typescript doesn't complain about internals being
|
||||
// "never".
|
||||
function checkIfElementInternalsSupportsAria(internals: ElementInternals) {
|
||||
return 'role' in internals;
|
||||
}
|
||||
|
@ -6,16 +6,7 @@
|
||||
|
||||
// import 'jasmine'; (google3-only)
|
||||
|
||||
import {html, LitElement} from 'lit';
|
||||
import {customElement} from 'lit/decorators.js';
|
||||
|
||||
import {
|
||||
ARIAProperty,
|
||||
ariaPropertyToAttribute,
|
||||
isAriaAttribute,
|
||||
polyfillARIAMixin,
|
||||
polyfillElementInternalsAria,
|
||||
} from './aria.js';
|
||||
import {ARIAProperty, ariaPropertyToAttribute, isAriaAttribute} from './aria.js';
|
||||
|
||||
describe('aria', () => {
|
||||
describe('isAriaAttribute()', () => {
|
||||
@ -51,277 +42,4 @@ describe('aria', () => {
|
||||
).toBe('aria-labelledby');
|
||||
});
|
||||
});
|
||||
|
||||
describe('polyfillARIAMixin()', () => {
|
||||
@customElement('test-setup-aria-host')
|
||||
class TestElement extends LitElement {
|
||||
static {
|
||||
polyfillARIAMixin(TestElement);
|
||||
}
|
||||
|
||||
override render() {
|
||||
return html`<slot></slot>`;
|
||||
}
|
||||
}
|
||||
|
||||
it('should reflect ARIAMixin properties to attributes', async () => {
|
||||
const element = new TestElement();
|
||||
document.body.appendChild(element);
|
||||
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();
|
||||
});
|
||||
});
|
||||
|
||||
describe('polyfillElementInternalsAria()', () => {
|
||||
@customElement('test-polyfill-element-internals-aria')
|
||||
class TestElement extends LitElement {
|
||||
static {
|
||||
polyfillARIAMixin(TestElement);
|
||||
}
|
||||
|
||||
internals = polyfillElementInternalsAria(this, this.attachInternals());
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.internals.role = 'button';
|
||||
}
|
||||
|
||||
override render() {
|
||||
return html`<slot></slot>`;
|
||||
}
|
||||
}
|
||||
|
||||
if ('role' in ElementInternals.prototype) {
|
||||
it('should not hydrate attributes when role set', () => {
|
||||
const element = new TestElement();
|
||||
document.body.appendChild(element);
|
||||
expect(element.hasAttribute('role'))
|
||||
.withContext('has role attribute')
|
||||
.toBeFalse();
|
||||
|
||||
element.remove();
|
||||
});
|
||||
} else {
|
||||
it('should preserve role values when set before connected', () => {
|
||||
const element = new TestElement();
|
||||
// TestElement() sets role in constructor
|
||||
expect(element.internals.role)
|
||||
.withContext('ElementInternals.role')
|
||||
.toEqual('button');
|
||||
});
|
||||
|
||||
it('should preserve aria values when set before connected', () => {
|
||||
const element = new TestElement();
|
||||
element.internals.ariaLabel = 'Foo';
|
||||
expect(element.internals.ariaLabel)
|
||||
.withContext('ElementInternals.ariaLabel')
|
||||
.toEqual('Foo');
|
||||
});
|
||||
|
||||
it('should hydrate role attributes when set before connection', async () => {
|
||||
const element = new TestElement();
|
||||
// TestElement() sets role in constructor
|
||||
document.body.appendChild(element);
|
||||
await element.updateComplete;
|
||||
expect(element.getAttribute('role'))
|
||||
.withContext('role attribute value')
|
||||
.toEqual('button');
|
||||
|
||||
element.remove();
|
||||
});
|
||||
|
||||
it('should hydrate aria attributes when set before connection', async () => {
|
||||
const element = new TestElement();
|
||||
element.internals.ariaLabel = 'Foo';
|
||||
document.body.appendChild(element);
|
||||
await element.updateComplete;
|
||||
expect(element.getAttribute('aria-label'))
|
||||
.withContext('aria-label attribute value')
|
||||
.toEqual('Foo');
|
||||
|
||||
element.remove();
|
||||
});
|
||||
|
||||
it('should set aria attributes when set after connection', async () => {
|
||||
const element = new TestElement();
|
||||
document.body.appendChild(element);
|
||||
element.internals.ariaLabel = 'Value after construction';
|
||||
await element.updateComplete;
|
||||
expect(element.getAttribute('aria-label'))
|
||||
.withContext('aria-label attribute value')
|
||||
.toEqual('Value after construction');
|
||||
|
||||
element.remove();
|
||||
});
|
||||
|
||||
it('should not override aria attributes on host when set before connection', async () => {
|
||||
const element = new TestElement();
|
||||
element.setAttribute('aria-label', 'Value set by user');
|
||||
element.internals.ariaLabel = 'Value set on internals';
|
||||
document.body.appendChild(element);
|
||||
await element.updateComplete;
|
||||
expect(element.getAttribute('aria-label'))
|
||||
.withContext('aria-label attribute value on host')
|
||||
.toEqual('Value set by user');
|
||||
expect(element.internals.ariaLabel)
|
||||
.withContext('ariaLabel internals property still the same')
|
||||
.toEqual('Value set on internals');
|
||||
|
||||
element.remove();
|
||||
});
|
||||
|
||||
it('should not override aria properties on host when set before connection', async () => {
|
||||
const element = new TestElement();
|
||||
element.ariaLabel = 'Value set by user';
|
||||
element.internals.ariaLabel = 'Value set on internals';
|
||||
document.body.appendChild(element);
|
||||
await element.updateComplete;
|
||||
expect(element.getAttribute('aria-label'))
|
||||
.withContext('aria-label attribute value on host')
|
||||
.toEqual('Value set by user');
|
||||
expect(element.ariaLabel)
|
||||
.withContext('ariaLabel property value on host')
|
||||
.toEqual('Value set by user');
|
||||
expect(element.internals.ariaLabel)
|
||||
.withContext('ariaLabel internals property still the same')
|
||||
.toEqual('Value set on internals');
|
||||
|
||||
element.remove();
|
||||
});
|
||||
|
||||
it('should not override role attribute on host when set before connection', async () => {
|
||||
const element = new TestElement();
|
||||
element.setAttribute('role', 'Value set by user');
|
||||
element.internals.role = 'Value set on internals';
|
||||
document.body.appendChild(element);
|
||||
await element.updateComplete;
|
||||
expect(element.getAttribute('role'))
|
||||
.withContext('role attribute value on host')
|
||||
.toEqual('Value set by user');
|
||||
expect(element.internals.role)
|
||||
.withContext('role internals property still the same')
|
||||
.toEqual('Value set on internals');
|
||||
|
||||
element.remove();
|
||||
});
|
||||
|
||||
it('should not override role property on host when set before connection', async () => {
|
||||
const element = new TestElement();
|
||||
element.role = 'Value set by user';
|
||||
element.internals.role = 'Value set on internals';
|
||||
document.body.appendChild(element);
|
||||
await element.updateComplete;
|
||||
expect(element.getAttribute('role'))
|
||||
.withContext('role attribute value on host')
|
||||
.toEqual('Value set by user');
|
||||
expect(element.role)
|
||||
.withContext('role property value on host')
|
||||
.toEqual('Value set by user');
|
||||
expect(element.internals.role)
|
||||
.withContext('role internals property still the same')
|
||||
.toEqual('Value set on internals');
|
||||
|
||||
element.remove();
|
||||
});
|
||||
|
||||
it('should handle setting role multiple times before connection', async () => {
|
||||
const element = new TestElement();
|
||||
element.internals.role = 'button';
|
||||
element.internals.role = 'checkbox';
|
||||
|
||||
expect(element.internals.role)
|
||||
.withContext('internals.role before connection')
|
||||
.toEqual('checkbox');
|
||||
document.body.appendChild(element);
|
||||
await element.updateComplete;
|
||||
expect(element.internals.role)
|
||||
.withContext('internals.role after connection')
|
||||
.toEqual('checkbox');
|
||||
|
||||
element.remove();
|
||||
});
|
||||
|
||||
it('should handle setting role multiple times before connection when property is set on host', async () => {
|
||||
const element = new TestElement();
|
||||
element.role = 'radio';
|
||||
element.internals.role = 'button';
|
||||
element.internals.role = 'checkbox';
|
||||
|
||||
expect(element.internals.role)
|
||||
.withContext('internals.role before connection')
|
||||
.toEqual('checkbox');
|
||||
document.body.appendChild(element);
|
||||
await element.updateComplete;
|
||||
expect(element.internals.role)
|
||||
.withContext('internals.role after connection')
|
||||
.toEqual('checkbox');
|
||||
|
||||
element.remove();
|
||||
});
|
||||
|
||||
it('should handle setting aria properties multiple times before connection', async () => {
|
||||
const element = new TestElement();
|
||||
element.internals.ariaLabel = 'First';
|
||||
element.internals.ariaLabel = 'Second';
|
||||
|
||||
expect(element.internals.ariaLabel)
|
||||
.withContext('internals.ariaLabel before connection')
|
||||
.toEqual('Second');
|
||||
document.body.appendChild(element);
|
||||
await element.updateComplete;
|
||||
expect(element.internals.ariaLabel)
|
||||
.withContext('internals.ariaLabel after connection')
|
||||
.toEqual('Second');
|
||||
|
||||
element.remove();
|
||||
});
|
||||
|
||||
it('should handle setting aria properties multiple times before connection when property is set on host', async () => {
|
||||
const element = new TestElement();
|
||||
element.ariaLabel = 'First';
|
||||
element.internals.ariaLabel = 'First';
|
||||
element.internals.ariaLabel = 'Second';
|
||||
|
||||
expect(element.internals.ariaLabel)
|
||||
.withContext('internals.ariaLabel before connection')
|
||||
.toEqual('Second');
|
||||
document.body.appendChild(element);
|
||||
await element.updateComplete;
|
||||
expect(element.internals.ariaLabel)
|
||||
.withContext('internals.ariaLabel after connection')
|
||||
.toEqual('Second');
|
||||
|
||||
element.remove();
|
||||
});
|
||||
|
||||
it('should handle setting role after first connection while disconnected', async () => {
|
||||
const element = new TestElement();
|
||||
element.internals.role = 'button';
|
||||
document.body.appendChild(element);
|
||||
await element.updateComplete;
|
||||
|
||||
element.remove();
|
||||
element.internals.role = 'checkbox';
|
||||
expect(element.internals.role)
|
||||
.withContext('internals.role after connected and disconnected')
|
||||
.toEqual('checkbox');
|
||||
document.body.appendChild(element);
|
||||
await element.updateComplete;
|
||||
expect(element.internals.role)
|
||||
.withContext('internals.role after reconnected')
|
||||
.toEqual('checkbox');
|
||||
|
||||
element.remove();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -6,10 +6,6 @@
|
||||
|
||||
import {LitElement} from 'lit';
|
||||
|
||||
import {
|
||||
polyfillARIAMixin,
|
||||
polyfillElementInternalsAria,
|
||||
} from '../../internal/aria/aria.js';
|
||||
import {MixinBase, MixinReturn} from './mixin.js';
|
||||
|
||||
/**
|
||||
@ -61,21 +57,12 @@ export function mixinElementInternals<T extends MixinBase<LitElement>>(
|
||||
extends base
|
||||
implements WithElementInternals
|
||||
{
|
||||
static {
|
||||
polyfillARIAMixin(
|
||||
WithElementInternalsElement as unknown as typeof LitElement,
|
||||
);
|
||||
}
|
||||
|
||||
get [internals]() {
|
||||
// Create internals in getter so that it can be used in methods called on
|
||||
// construction in `ReactiveElement`, such as `requestUpdate()`.
|
||||
if (!this[privateInternals]) {
|
||||
// Cast needed for closure
|
||||
this[privateInternals] = polyfillElementInternalsAria(
|
||||
this,
|
||||
(this as HTMLElement).attachInternals(),
|
||||
);
|
||||
this[privateInternals] = (this as HTMLElement).attachInternals();
|
||||
}
|
||||
|
||||
return this[privateInternals];
|
||||
|
@ -7,11 +7,6 @@
|
||||
import {html, isServer, LitElement} from 'lit';
|
||||
import {queryAssignedElements} from 'lit/decorators.js';
|
||||
|
||||
import {
|
||||
polyfillARIAMixin,
|
||||
polyfillElementInternalsAria,
|
||||
} from '../../internal/aria/aria.js';
|
||||
|
||||
import {ListController, NavigableKeys} from './list-controller.js';
|
||||
import {ListItem as SharedListItem} from './list-navigation-helpers.js';
|
||||
|
||||
@ -23,10 +18,6 @@ interface ListItem extends SharedListItem {
|
||||
|
||||
// tslint:disable-next-line:enforce-comments-on-exported-symbols
|
||||
export class List extends LitElement {
|
||||
static {
|
||||
polyfillARIAMixin(List);
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of activatable and disableable list items. Queries every assigned
|
||||
* element that has the `md-list-item` attribute.
|
||||
@ -58,11 +49,9 @@ export class List extends LitElement {
|
||||
isActivatable: (item) => !item.disabled && item.type !== 'text',
|
||||
});
|
||||
|
||||
private readonly internals = polyfillElementInternalsAria(
|
||||
this,
|
||||
private readonly internals =
|
||||
// Cast needed for closure
|
||||
(this as HTMLElement).attachInternals(),
|
||||
);
|
||||
(this as HTMLElement).attachInternals();
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
@ -12,10 +12,6 @@ import {property, query, queryAssignedElements, state} from 'lit/decorators.js';
|
||||
import {ClassInfo, classMap} from 'lit/directives/class-map.js';
|
||||
import {styleMap} from 'lit/directives/style-map.js';
|
||||
|
||||
import {
|
||||
polyfillARIAMixin,
|
||||
polyfillElementInternalsAria,
|
||||
} from '../../internal/aria/aria.js';
|
||||
import {EASING, createAnimationSignal} from '../../internal/motion/animation.js';
|
||||
import {
|
||||
ListController,
|
||||
@ -90,10 +86,6 @@ function getFocusedElement(
|
||||
* @fires closed {Event} Fired once the menu is closed, after any animations
|
||||
*/
|
||||
export abstract class Menu extends LitElement {
|
||||
static {
|
||||
polyfillARIAMixin(Menu);
|
||||
}
|
||||
|
||||
@query('.menu') private readonly surfaceEl!: HTMLElement | null;
|
||||
@query('slot') private readonly slotEl!: HTMLSlotElement | null;
|
||||
|
||||
@ -341,11 +333,9 @@ export abstract class Menu extends LitElement {
|
||||
this.requestUpdate('anchorElement');
|
||||
}
|
||||
|
||||
private readonly internals = polyfillElementInternalsAria(
|
||||
this,
|
||||
private readonly internals =
|
||||
// Cast needed for closure
|
||||
(this as HTMLElement).attachInternals(),
|
||||
);
|
||||
(this as HTMLElement).attachInternals();
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
@ -18,10 +18,6 @@ import {
|
||||
} from 'lit/decorators.js';
|
||||
import {ClassInfo, classMap} from 'lit/directives/class-map.js';
|
||||
|
||||
import {
|
||||
polyfillARIAMixin,
|
||||
polyfillElementInternalsAria,
|
||||
} from '../../internal/aria/aria.js';
|
||||
import {EASING} from '../../internal/motion/animation.js';
|
||||
import {mixinFocusable} from '../../labs/behaviors/focusable.js';
|
||||
|
||||
@ -44,10 +40,6 @@ const tabBaseClass = mixinFocusable(LitElement);
|
||||
* Tab component.
|
||||
*/
|
||||
export class Tab extends tabBaseClass {
|
||||
static {
|
||||
polyfillARIAMixin(Tab);
|
||||
}
|
||||
|
||||
/**
|
||||
* The attribute `md-tab` indicates that the element is a tab for the parent
|
||||
* element, `<md-tabs>`. Make sure if you're implementing your own `md-tab`
|
||||
@ -89,11 +81,9 @@ export class Tab extends tabBaseClass {
|
||||
private readonly assignedDefaultNodes!: Node[];
|
||||
@queryAssignedElements({slot: 'icon', flatten: true})
|
||||
private readonly assignedIcons!: HTMLElement[];
|
||||
private readonly internals = polyfillElementInternalsAria(
|
||||
this,
|
||||
private readonly internals =
|
||||
// Cast needed for closure
|
||||
(this as HTMLElement).attachInternals(),
|
||||
);
|
||||
(this as HTMLElement).attachInternals();
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
@ -9,11 +9,6 @@ import '../../divider/divider.js';
|
||||
import {html, isServer, LitElement} from 'lit';
|
||||
import {property, query, queryAssignedElements} from 'lit/decorators.js';
|
||||
|
||||
import {
|
||||
polyfillARIAMixin,
|
||||
polyfillElementInternalsAria,
|
||||
} from '../../internal/aria/aria.js';
|
||||
|
||||
import {ANIMATE_INDICATOR, Tab} from './tab.js';
|
||||
|
||||
/**
|
||||
@ -41,10 +36,6 @@ import {ANIMATE_INDICATOR, Tab} from './tab.js';
|
||||
*
|
||||
*/
|
||||
export class Tabs extends LitElement {
|
||||
static {
|
||||
polyfillARIAMixin(Tabs);
|
||||
}
|
||||
|
||||
/**
|
||||
* The tabs of this tab bar.
|
||||
*/
|
||||
@ -117,11 +108,9 @@ export class Tabs extends LitElement {
|
||||
return this.tabs.find((tab) => tab.matches(':focus-within'));
|
||||
}
|
||||
|
||||
private readonly internals = polyfillElementInternalsAria(
|
||||
this,
|
||||
private readonly internals =
|
||||
// Cast needed for closure
|
||||
(this as HTMLElement).attachInternals(),
|
||||
);
|
||||
(this as HTMLElement).attachInternals();
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
Loading…
Reference in New Issue
Block a user