UNPKG

@polymer/lit-element

Version:

Polymer based lit-html custom element

158 lines 6.95 kB
/** * @license * Copyright (c) 2017 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 { TemplateResult } from 'lit-html'; import { render } from 'lit-html/lib/shady-render'; import { UpdatingElement } from './lib/updating-element.js'; export * from './lib/updating-element.js'; export * from './lib/decorators.js'; export { html, svg, TemplateResult, SVGTemplateResult } from 'lit-html/lit-html'; import { supportsAdoptingStyleSheets } from './lib/css-tag.js'; export * from './lib/css-tag.js'; export class LitElement extends UpdatingElement { /** * Array of styles to apply to the element. The styles should be defined * using the `css` tag function. */ static get styles() { return []; } static get _uniqueStyles() { if (this._styles === undefined) { const styles = this.styles; // As a performance optimization to avoid duplicated styling that can // occur especially when composing via subclassing, de-duplicate styles // preserving the last item in the list. The last item is kept to // try to preserve cascade order with the assumption that it's most // important that last added styles override previous styles. const styleSet = styles.reduceRight((set, s) => { set.add(s); // on IE set.add does not return the set. return set; }, new Set()); // Array.form does not work on Set in IE this._styles = []; styleSet.forEach((v) => this._styles.unshift(v)); } return this._styles; } /** * Performs element initialization. By default this calls `createRenderRoot` * to create the element `renderRoot` node and captures any pre-set values for * registered properties. */ initialize() { super.initialize(); this.renderRoot = this.createRenderRoot(); // Note, if renderRoot is not a shadowRoot, styles would/could apply to the // element's getRootNode(). While this could be done, we're choosing not to // support this now since it would require different logic around de-duping. if (window.ShadowRoot && this.renderRoot instanceof window.ShadowRoot) { this.adoptStyles(); } } /** * Returns the node into which the element should render and by default * creates and returns an open shadowRoot. Implement to customize where the * element's DOM is rendered. For example, to render into the element's * childNodes, return `this`. * @returns {Element|DocumentFragment} Returns a node into which to render. */ createRenderRoot() { return this.attachShadow({ mode: 'open' }); } /** * Applies styling to the element shadowRoot using the `static get styles` * property. Styling will apply using `shadowRoot.adoptedStyleSheets` where * available and will fallback otherwise. When Shadow DOM is polyfilled, * ShadyCSS scopes styles and adds them to the document. When Shadow DOM * is available but `adoptedStyleSheets` is not, styles are appended to the * end of the `shadowRoot` to [mimic spec * behavior](https://wicg.github.io/construct-stylesheets/#using-constructed-stylesheets). */ adoptStyles() { const styles = this.constructor._uniqueStyles; if (styles.length === 0) { return; } // There are three separate cases here based on Shadow DOM support. // (1) shadowRoot polyfilled: use ShadyCSS // (2) shadowRoot.adoptedStyleSheets available: use it. // (3) shadowRoot.adoptedStyleSheets polyfilled: append styles after // rendering if (window.ShadyCSS !== undefined && !window.ShadyCSS.nativeShadow) { window.ShadyCSS.ScopingShim.prepareAdoptedCssText(styles.map((s) => s.cssText), this.localName); } else if (supportsAdoptingStyleSheets) { this.renderRoot.adoptedStyleSheets = styles.map((s) => s.styleSheet); } else { // This must be done after rendering so the actual style insertion is done // in `update`. this._needsShimAdoptedStyleSheets = true; } } connectedCallback() { super.connectedCallback(); // Note, first update/render handles styleElement so we only call this if // connected after first update. if (this.hasUpdated && window.ShadyCSS !== undefined) { window.ShadyCSS.styleElement(this); } } /** * Updates the element. This method reflects property values to attributes * and calls `render` to render DOM via lit-html. Setting properties inside * this method will *not* trigger another update. * * @param _changedProperties Map of changed properties with old values */ update(changedProperties) { super.update(changedProperties); const templateResult = this.render(); if (templateResult instanceof TemplateResult) { this.constructor .render(templateResult, this.renderRoot, { scopeName: this.localName, eventContext: this }); } // When native Shadow DOM is used but adoptedStyles are not supported, // insert styling after rendering to ensure adoptedStyles have highest // priority. if (this._needsShimAdoptedStyleSheets) { this._needsShimAdoptedStyleSheets = false; this.constructor._uniqueStyles.forEach((s) => { const style = document.createElement('style'); style.textContent = s.cssText; this.renderRoot.appendChild(style); }); } } /** * Invoked on each update to perform rendering tasks. This method must return * a lit-html TemplateResult. Setting properties inside this method will *not* * trigger the element to update. */ render() { } } /** * Ensure this class is marked as `finalized` as an optimization ensuring * it will not needlessly try to `finalize`. */ LitElement.finalized = true; /** * Render method used to render the lit-html TemplateResult to the element's * DOM. * @param {TemplateResult} Template to render. * @param {Element|DocumentFragment} Node into which to render. * @param {String} Element name. * @nocollapse */ LitElement.render = render; //# sourceMappingURL=lit-element.js.map