import { dedupeMixin } from '@lion/core'; import { FormControlMixin } from './FormControlMixin.js'; /** * @typedef {import('../types/FocusMixinTypes').FocusMixin} FocusMixin * @type {FocusMixin} * @param {import('@open-wc/dedupe-mixin').Constructor} superclass */ const FocusMixinImplementation = superclass => // @ts-expect-error false positive for incompatible static get properties. Lit-element merges super properties already for you. // eslint-disable-next-line no-unused-vars, max-len, no-shadow class FocusMixin extends FormControlMixin(superclass) { static get properties() { return { focused: { type: Boolean, reflect: true, }, }; } constructor() { super(); this.focused = false; } connectedCallback() { super.connectedCallback(); this.__registerEventsForFocusMixin(); } disconnectedCallback() { super.disconnectedCallback(); this.__teardownEventsForFocusMixin(); } focus() { const native = this._inputNode; if (native) { native.focus(); } } blur() { const native = this._inputNode; if (native) { native.blur(); } } __onFocus() { this.focused = true; } __onBlur() { this.focused = false; } __registerEventsForFocusMixin() { /** * focus * @param {Event} ev */ this.__redispatchFocus = ev => { ev.stopPropagation(); this.dispatchEvent(new Event('focus')); }; this._inputNode.addEventListener('focus', this.__redispatchFocus); /** * blur * @param {Event} ev */ this.__redispatchBlur = ev => { ev.stopPropagation(); this.dispatchEvent(new Event('blur')); }; this._inputNode.addEventListener('blur', this.__redispatchBlur); /** * focusin * @param {Event} ev */ this.__redispatchFocusin = ev => { ev.stopPropagation(); this.__onFocus(); this.dispatchEvent(new Event('focusin', { bubbles: true, composed: true })); }; this._inputNode.addEventListener('focusin', this.__redispatchFocusin); /** * focusout * @param {Event} ev */ this.__redispatchFocusout = ev => { ev.stopPropagation(); this.__onBlur(); this.dispatchEvent(new Event('focusout', { bubbles: true, composed: true })); }; this._inputNode.addEventListener('focusout', this.__redispatchFocusout); } __teardownEventsForFocusMixin() { this._inputNode.removeEventListener( 'focus', /** @type {EventListenerOrEventListenerObject} */ (this.__redispatchFocus), ); this._inputNode.removeEventListener( 'blur', /** @type {EventListenerOrEventListenerObject} */ (this.__redispatchBlur), ); this._inputNode.removeEventListener( 'focusin', /** @type {EventListenerOrEventListenerObject} */ (this.__redispatchFocusin), ); this._inputNode.removeEventListener( 'focusout', /** @type {EventListenerOrEventListenerObject} */ (this.__redispatchFocusout), ); } }; export const FocusMixin = dedupeMixin(FocusMixinImplementation);