/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { __decorate } from "tslib";
import { isServer, LitElement } from 'lit';
import { property } from 'lit/decorators.js';
import { AttachableController, } from '../../internal/controller/attachable-controller.js';
/**
* Events that the focus ring listens to.
*/
const EVENTS = ['focusin', 'focusout', 'pointerdown'];
/**
* A focus ring component.
*
* @fires visibility-changed {Event} Fired whenever `visible` changes.
*/
export class FocusRing extends LitElement {
constructor() {
super(...arguments);
/**
* Makes the focus ring visible.
*/
this.visible = false;
/**
* Makes the focus ring animate inwards instead of outwards.
*/
this.inward = false;
this.attachableController = new AttachableController(this, this.onControlChange.bind(this));
}
get htmlFor() {
return this.attachableController.htmlFor;
}
set htmlFor(htmlFor) {
this.attachableController.htmlFor = htmlFor;
}
get control() {
return this.attachableController.control;
}
set control(control) {
this.attachableController.control = control;
}
attach(control) {
this.attachableController.attach(control);
}
detach() {
this.attachableController.detach();
}
connectedCallback() {
super.connectedCallback();
// Needed for VoiceOver, which will create a "group" if the element is a
// sibling to other content.
this.setAttribute('aria-hidden', 'true');
}
/** @private */
handleEvent(event) {
if (event[HANDLED_BY_FOCUS_RING]) {
// This ensures the focus ring does not activate when multiple focus rings
// are used within a single component.
return;
}
switch (event.type) {
default:
return;
case 'focusin':
this.visible = this.control?.matches(':focus-visible') ?? false;
break;
case 'focusout':
case 'pointerdown':
this.visible = false;
break;
}
event[HANDLED_BY_FOCUS_RING] = true;
}
onControlChange(prev, next) {
if (isServer)
return;
for (const event of EVENTS) {
prev?.removeEventListener(event, this);
next?.addEventListener(event, this);
}
}
update(changed) {
if (changed.has('visible')) {
// This logic can be removed once the `:has` selector has been introduced
// to Firefox. This is necessary to allow correct submenu styles.
this.dispatchEvent(new Event('visibility-changed'));
}
super.update(changed);
}
}
__decorate([
property({ type: Boolean, reflect: true })
], FocusRing.prototype, "visible", void 0);
__decorate([
property({ type: Boolean, reflect: true })
], FocusRing.prototype, "inward", void 0);
const HANDLED_BY_FOCUS_RING = Symbol('handledByFocusRing');
//# sourceMappingURL=focus-ring.js.map