1 | /**
|
2 | * @license
|
3 | * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
|
4 | * This code may only be used under the BSD style license found at
|
5 | * http://polymer.github.io/LICENSE.txt
|
6 | * The complete set of authors may be found at
|
7 | * http://polymer.github.io/AUTHORS.txt
|
8 | * The complete set of contributors may be found at
|
9 | * http://polymer.github.io/CONTRIBUTORS.txt
|
10 | * Code distributed by Google as part of the polymer project is also
|
11 | * subject to an additional IP rights grant found at
|
12 | * http://polymer.github.io/PATENTS.txt
|
13 | */
|
14 | import { render } from 'lit-html/lib/shady-render.js';
|
15 | import { UpdatingElement } from './lib/updating-element.js';
|
16 | export * from './lib/updating-element.js';
|
17 | export * from './lib/decorators.js';
|
18 | export { html, svg, TemplateResult, SVGTemplateResult } from 'lit-html/lit-html.js';
|
19 | import { supportsAdoptingStyleSheets } from './lib/css-tag.js';
|
20 | export * from './lib/css-tag.js';
|
21 | // IMPORTANT: do not change the property name or the assignment expression.
|
22 | // This line will be used in regexes to search for LitElement usage.
|
23 | // TODO(justinfagnani): inject version number at build time
|
24 | (window['litElementVersions'] || (window['litElementVersions'] = []))
|
25 | .push('2.3.1');
|
26 | /**
|
27 | * Sentinal value used to avoid calling lit-html's render function when
|
28 | * subclasses do not implement `render`
|
29 | */
|
30 | const renderNotImplemented = {};
|
31 | export class LitElement extends UpdatingElement {
|
32 | /**
|
33 | * Return the array of styles to apply to the element.
|
34 | * Override this method to integrate into a style management system.
|
35 | *
|
36 | * @nocollapse
|
37 | */
|
38 | static getStyles() {
|
39 | return this.styles;
|
40 | }
|
41 | /** @nocollapse */
|
42 | static _getUniqueStyles() {
|
43 | // Only gather styles once per class
|
44 | if (this.hasOwnProperty(JSCompiler_renameProperty('_styles', this))) {
|
45 | return;
|
46 | }
|
47 | // Take care not to call `this.getStyles()` multiple times since this
|
48 | // generates new CSSResults each time.
|
49 | // TODO(sorvell): Since we do not cache CSSResults by input, any
|
50 | // shared styles will generate new stylesheet objects, which is wasteful.
|
51 | // This should be addressed when a browser ships constructable
|
52 | // stylesheets.
|
53 | const userStyles = this.getStyles();
|
54 | if (userStyles === undefined) {
|
55 | this._styles = [];
|
56 | }
|
57 | else if (Array.isArray(userStyles)) {
|
58 | // De-duplicate styles preserving the _last_ instance in the set.
|
59 | // This is a performance optimization to avoid duplicated styles that can
|
60 | // occur especially when composing via subclassing.
|
61 | // The last item is kept to try to preserve the cascade order with the
|
62 | // assumption that it's most important that last added styles override
|
63 | // previous styles.
|
64 | const addStyles = (styles, set) => styles.reduceRight((set, s) =>
|
65 | // Note: On IE set.add() does not return the set
|
66 | Array.isArray(s) ? addStyles(s, set) : (set.add(s), set), set);
|
67 | // Array.from does not work on Set in IE, otherwise return
|
68 | // Array.from(addStyles(userStyles, new Set<CSSResult>())).reverse()
|
69 | const set = addStyles(userStyles, new Set());
|
70 | const styles = [];
|
71 | set.forEach((v) => styles.unshift(v));
|
72 | this._styles = styles;
|
73 | }
|
74 | else {
|
75 | this._styles = [userStyles];
|
76 | }
|
77 | }
|
78 | /**
|
79 | * Performs element initialization. By default this calls `createRenderRoot`
|
80 | * to create the element `renderRoot` node and captures any pre-set values for
|
81 | * registered properties.
|
82 | */
|
83 | initialize() {
|
84 | super.initialize();
|
85 | this.constructor._getUniqueStyles();
|
86 | this.renderRoot =
|
87 | this.createRenderRoot();
|
88 | // Note, if renderRoot is not a shadowRoot, styles would/could apply to the
|
89 | // element's getRootNode(). While this could be done, we're choosing not to
|
90 | // support this now since it would require different logic around de-duping.
|
91 | if (window.ShadowRoot && this.renderRoot instanceof window.ShadowRoot) {
|
92 | this.adoptStyles();
|
93 | }
|
94 | }
|
95 | /**
|
96 | * Returns the node into which the element should render and by default
|
97 | * creates and returns an open shadowRoot. Implement to customize where the
|
98 | * element's DOM is rendered. For example, to render into the element's
|
99 | * childNodes, return `this`.
|
100 | * @returns {Element|DocumentFragment} Returns a node into which to render.
|
101 | */
|
102 | createRenderRoot() {
|
103 | return this.attachShadow({ mode: 'open' });
|
104 | }
|
105 | /**
|
106 | * Applies styling to the element shadowRoot using the `static get styles`
|
107 | * property. Styling will apply using `shadowRoot.adoptedStyleSheets` where
|
108 | * available and will fallback otherwise. When Shadow DOM is polyfilled,
|
109 | * ShadyCSS scopes styles and adds them to the document. When Shadow DOM
|
110 | * is available but `adoptedStyleSheets` is not, styles are appended to the
|
111 | * end of the `shadowRoot` to [mimic spec
|
112 | * behavior](https://wicg.github.io/construct-stylesheets/#using-constructed-stylesheets).
|
113 | */
|
114 | adoptStyles() {
|
115 | const styles = this.constructor._styles;
|
116 | if (styles.length === 0) {
|
117 | return;
|
118 | }
|
119 | // There are three separate cases here based on Shadow DOM support.
|
120 | // (1) shadowRoot polyfilled: use ShadyCSS
|
121 | // (2) shadowRoot.adoptedStyleSheets available: use it.
|
122 | // (3) shadowRoot.adoptedStyleSheets polyfilled: append styles after
|
123 | // rendering
|
124 | if (window.ShadyCSS !== undefined && !window.ShadyCSS.nativeShadow) {
|
125 | window.ShadyCSS.ScopingShim.prepareAdoptedCssText(styles.map((s) => s.cssText), this.localName);
|
126 | }
|
127 | else if (supportsAdoptingStyleSheets) {
|
128 | this.renderRoot.adoptedStyleSheets =
|
129 | styles.map((s) => s.styleSheet);
|
130 | }
|
131 | else {
|
132 | // This must be done after rendering so the actual style insertion is done
|
133 | // in `update`.
|
134 | this._needsShimAdoptedStyleSheets = true;
|
135 | }
|
136 | }
|
137 | connectedCallback() {
|
138 | super.connectedCallback();
|
139 | // Note, first update/render handles styleElement so we only call this if
|
140 | // connected after first update.
|
141 | if (this.hasUpdated && window.ShadyCSS !== undefined) {
|
142 | window.ShadyCSS.styleElement(this);
|
143 | }
|
144 | }
|
145 | /**
|
146 | * Updates the element. This method reflects property values to attributes
|
147 | * and calls `render` to render DOM via lit-html. Setting properties inside
|
148 | * this method will *not* trigger another update.
|
149 | * @param _changedProperties Map of changed properties with old values
|
150 | */
|
151 | update(changedProperties) {
|
152 | // Setting properties in `render` should not trigger an update. Since
|
153 | // updates are allowed after super.update, it's important to call `render`
|
154 | // before that.
|
155 | const templateResult = this.render();
|
156 | super.update(changedProperties);
|
157 | // If render is not implemented by the component, don't call lit-html render
|
158 | if (templateResult !== renderNotImplemented) {
|
159 | this.constructor
|
160 | .render(templateResult, this.renderRoot, { scopeName: this.localName, eventContext: this });
|
161 | }
|
162 | // When native Shadow DOM is used but adoptedStyles are not supported,
|
163 | // insert styling after rendering to ensure adoptedStyles have highest
|
164 | // priority.
|
165 | if (this._needsShimAdoptedStyleSheets) {
|
166 | this._needsShimAdoptedStyleSheets = false;
|
167 | this.constructor._styles.forEach((s) => {
|
168 | const style = document.createElement('style');
|
169 | style.textContent = s.cssText;
|
170 | this.renderRoot.appendChild(style);
|
171 | });
|
172 | }
|
173 | }
|
174 | /**
|
175 | * Invoked on each update to perform rendering tasks. This method may return
|
176 | * any value renderable by lit-html's NodePart - typically a TemplateResult.
|
177 | * Setting properties inside this method will *not* trigger the element to
|
178 | * update.
|
179 | */
|
180 | render() {
|
181 | return renderNotImplemented;
|
182 | }
|
183 | }
|
184 | /**
|
185 | * Ensure this class is marked as `finalized` as an optimization ensuring
|
186 | * it will not needlessly try to `finalize`.
|
187 | *
|
188 | * Note this property name is a string to prevent breaking Closure JS Compiler
|
189 | * optimizations. See updating-element.ts for more information.
|
190 | */
|
191 | LitElement['finalized'] = true;
|
192 | /**
|
193 | * Render method used to render the value to the element's DOM.
|
194 | * @param result The value to render.
|
195 | * @param container Node into which to render.
|
196 | * @param options Element name.
|
197 | * @nocollapse
|
198 | */
|
199 | LitElement.render = render;
|
200 | //# sourceMappingURL=lit-element.js.map |
\ | No newline at end of file |