| // Copyright 2017 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import {dedupingMixin, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; |
| |
| export const HIDE_FOCUS_RING_ATTRIBUTE = 'hide-focus-ring'; |
| |
| type Constructor<T> = new ( ...args: any[]) => T; |
| |
| /** |
| * Behavior which adds the 'hide-focus-ring' attribute to a target element |
| * when the user interacts with it using the mouse, allowing the focus outline |
| * to be hidden without affecting keyboard users. |
| */ |
| export const MouseFocusMixin = dedupingMixin( |
| <T extends Constructor<PolymerElement>>(superClass: T): T& |
| Constructor<MouseFocusMixinInterface> => { |
| class MouseFocusMixin extends superClass { |
| private boundOnMousedown_: (e: Event) => void; |
| boundOnKeydown: (e: KeyboardEvent) => void; |
| |
| override connectedCallback() { |
| super.connectedCallback(); |
| this.boundOnMousedown_ = this.onMousedown_.bind(this); |
| this.boundOnKeydown = this.onKeydown_.bind(this); |
| |
| // These events are added to the document because capture doesn't work |
| // properly when listeners are added to a Polymer element, because the |
| // event is considered AT_TARGET for the element, and is evaluated |
| // after inner captures. |
| document.addEventListener('mousedown', this.boundOnMousedown_, true); |
| document.addEventListener('keydown', this.boundOnKeydown, true); |
| } |
| |
| override disconnectedCallback() { |
| super.disconnectedCallback(); |
| document.removeEventListener( |
| 'mousedown', this.boundOnMousedown_, true); |
| document.removeEventListener( |
| 'keydown', this.boundOnKeydown, true); |
| } |
| |
| private onMousedown_() { |
| this.setAttribute(HIDE_FOCUS_RING_ATTRIBUTE, ''); |
| } |
| |
| private onKeydown_(e: KeyboardEvent) { |
| if (!['Shift', 'Alt', 'Control', 'Meta'].includes(e.key)) { |
| this.removeAttribute(HIDE_FOCUS_RING_ATTRIBUTE); |
| } |
| } |
| } |
| |
| return MouseFocusMixin; |
| }); |
| |
| export interface MouseFocusMixinInterface { |
| boundOnKeydown: (e: KeyboardEvent) => void; |
| } |