UNPKG

@advanced-rest-client/arc-overlay-mixin

Version:

arc-overlay-mixin is a port of iron-overlay-behavior that works with web components

193 lines (168 loc) 5.1 kB
/** @license Copyright (c) 2015 The Polymer Project Authors. All rights reserved. This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as part of the polymer project is also subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt */ import { LitElement, html, css } from 'lit-element'; /* eslint-disable class-methods-use-this */ /* eslint-disable no-plusplus */ /* eslint-disable no-continue */ /* `arc-overlay-backdrop` is a backdrop used by `ArcOverlayMixin`. It should be a singleton. Originally designed by the Polymer team, ported to LitElement by ARC team. ### Styling The following custom properties and mixins are available for styling. Custom property | Description | Default -------------------------------------------|------------------------|--------- `--iron-overlay-backdrop-background-color` | Backdrop background color | #000 `--iron-overlay-backdrop-opacity` | Backdrop opacity | 0.6 `--iron-overlay-backdrop` | Mixin applied to `iron-overlay-backdrop`. | {} `--iron-overlay-backdrop-opened` | Mixin applied to `iron-overlay-backdrop` when it is displayed | {} */ export class ArcOverlayBackdrop extends LitElement { get styles() { return css` :host { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: var(--arc-overlay-backdrop-background-color, var(--iron-overlay-backdrop-background-color, #000)); opacity: 0; transition: var(--arc-overlay-backdrop-transition, opacity 0.2s); pointer-events: none; } :host(.opened) { opacity: var(--arc-overlay-backdrop-opacity, var(--iron-overlay-backdrop-opacity, 0.6)); pointer-events: auto; }`; } static get properties() { return { opened: { type: Boolean, reflect: true } }; } get opened() { return this.__opened; } set opened(value) { const old = this.__opened; if (old === value) { return; } this.__opened = value; this._openedChanged(value); } constructor() { super(); this.opened = false; // Used to cancel previous requestAnimationFrame calls when opened changes. this.__openedRaf = null; this._onTransitionend = this._onTransitionend.bind(this); } connectedCallback() { this.isAttached = true; super.connectedCallback(); this.addEventListener('transitionend', this._onTransitionend, true); if (this.opened) { this._openedChanged(this.opened); } } disconnectedCallback() { this.isAttached = false; super.disconnectedCallback(); this.removeEventListener('transitionend', this._onTransitionend); } /** * Appends the backdrop to document body if needed. */ prepare() { if (this.opened && !this.parentNode) { document.body.appendChild(this); } } /** * Shows the backdrop. */ open() { this.opened = true; } /** * Hides the backdrop. */ close() { this.opened = false; } /** * Removes the backdrop from document body if needed. */ complete() { if (!this.opened && this.parentNode === document.body) { this.parentNode.removeChild(this); } } _onTransitionend(e) { if (e && e.target === this) { this.complete(); } } /** * @param {boolean} opened * @private */ _openedChanged(opened) { if (opened) { // Auto-attach. this.prepare(); } else { // Animation might be disabled via the mixin or opacity custom property. // If it is disabled in other ways, it's up to the user to call complete. const cs = window.getComputedStyle(this); if (cs.transitionDuration === '0s' || cs.opacity === '0') { this.complete(); } } if (!this.isAttached) { return; } // Always cancel previous requestAnimationFrame. if (this.__openedRaf) { window.cancelAnimationFrame(this.__openedRaf); this.__openedRaf = null; } // Force relayout to ensure proper transitions. const { scrollTop } = this; this.scrollTop = undefined; this.scrollTop = scrollTop; this.__openedRaf = window.requestAnimationFrame(() => { this.__openedRaf = null; this.toggleClass('opened', this.opened); }); } /** * Toggles class on this element. * @param {String} klass CSS class name to toggle * @param {Boolean} condition Boolean condition to test whether the class should be * added or removed. */ toggleClass(klass, condition) { if (condition) { if (!this.classList.contains(klass)) { this.classList.add(klass); } } else if (this.classList.contains(klass)) { this.classList.remove(klass); } } render() { return html`<style>${this.styles}</style><slot></slot>`; } }