UNPKG

@material/web

Version:
100 lines 3.16 kB
/** * @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