UNPKG

@aire-ux/aire-overlay

Version:
156 lines (142 loc) 4.32 kB
import '@polymer/polymer/lib/elements/dom-if.js'; import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { Debouncer } from '@polymer/polymer/lib/utils/debounce.js'; import { idlePeriod } from '@polymer/polymer/lib/utils/async.js'; import { PolymerElement } from '@polymer/polymer/polymer-element.js'; class FlowComponentRenderer extends PolymerElement { static get template() { return html` <style> :host { animation: 1ms flow-component-renderer-appear; } @keyframes flow-component-renderer-appear { to { opacity: 1; } } </style> <slot></slot> `; } static get is() { return 'flow-component-renderer'; } static get properties() { return { nodeid: Number, appid: String, }; } static get observers() { return ['_attachRenderedComponentIfAble(appid, nodeid)']; } ready() { super.ready(); this.addEventListener('click', function (event) { if ( this.firstChild && typeof this.firstChild.click === 'function' && event.target === this ) { event.stopPropagation(); this.firstChild.click(); } }); this.addEventListener('animationend', this._onAnimationEnd); } _asyncAttachRenderedComponentIfAble() { this._debouncer = Debouncer.debounce(this._debouncer, idlePeriod, () => this._attachRenderedComponentIfAble() ); } _attachRenderedComponentIfAble() { if (!this.nodeid || !this.appid) { return; } const renderedComponent = this._getRenderedComponent(); if (this.firstChild) { if (!renderedComponent) { this._asyncAttachRenderedComponentIfAble(); } else if (this.firstChild !== renderedComponent) { this.replaceChild(renderedComponent, this.firstChild); this._defineFocusTarget(); this.onComponentRendered(); } else { this._defineFocusTarget(); this.onComponentRendered(); } } else { if (renderedComponent) { this.appendChild(renderedComponent); this._defineFocusTarget(); this.onComponentRendered(); } else { this._asyncAttachRenderedComponentIfAble(); } } } _getRenderedComponent() { try { return window.Vaadin.Flow.clients[this.appid].getByNodeId(this.nodeid); } catch (error) { console.error( 'Could not get node %s from app %s', this.nodeid, this.appid ); console.error(error); } return null; } onComponentRendered() { // subclasses can override this method to execute custom logic on resize } /* Setting the `focus-target` attribute to the first focusable descendant starting from the firstChild necessary for the focus to be delegated within the flow-component-renderer when used inside a vaadin-grid cell */ _defineFocusTarget() { var focusable = this._getFirstFocusableDescendant(this.firstChild); if (focusable !== null) { focusable.setAttribute('focus-target', 'true'); } } _getFirstFocusableDescendant(node) { if (this._isFocusable(node)) { return node; } if (node.hasAttribute && (node.hasAttribute('disabled') || node.hasAttribute('hidden'))) { return null; } if (!node.children) { return null; } for (var i = 0; i < node.children.length; i++) { var focusable = this._getFirstFocusableDescendant(node.children[i]); if (focusable !== null) { return focusable; } } return null; } _isFocusable(node) { if ( node.hasAttribute && typeof node.hasAttribute === 'function' && (node.hasAttribute('disabled') || node.hasAttribute('hidden')) ) { return false; } return node.tabIndex === 0; } _onAnimationEnd(e) { // ShadyCSS applies scoping suffixes to animation names // To ensure that child is attached once element is unhidden // for when it was filtered out from, eg, ComboBox // https://github.com/vaadin/vaadin-flow-components/issues/437 if (e.animationName.indexOf('flow-component-renderer-appear') === 0) { this._attachRenderedComponentIfAble(); } } } window.customElements.define(FlowComponentRenderer.is, FlowComponentRenderer);