Commit 50f62bae authored by Benjamin Franzke's avatar Benjamin Franzke Committed by Oliver Hader
Browse files

[FEATURE] Introduce lit-html & lit-element as client-side template engine

Add the lit-html template engine, that originated from
the polymer project and is now base for web components
together with the web component base case LitElement.

It is used to replace string-concatenation/jquery based
templating in order to adapt to modern web standards.

typo3/testing-framework is adapted to include lit-html and
lit-element with:
https://github.com/TYPO3/testing-framework/pull/221
(releases as 6.6.0 and merged in #93074)

Commands:

  yarn add lit-html@^1.3 lit-element@^2.4
  yarn add --dev grunt-rollup
  grunt build

Resolves: #91810
Related: #93074
Releases: master
Change-Id: If419d378d6e98c150b219fe441b0766d12e9b639
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/67092

Tested-by: default avatarTYPO3com <noreply@typo3.com>
Tested-by: Oliver Hader's avatarOliver Hader <oliver.hader@typo3.org>
Reviewed-by: Oliver Hader's avatarOliver Hader <oliver.hader@typo3.org>
parent f1766832
......@@ -449,6 +449,72 @@ module.exports = function (grunt) {
cache: './.cache/grunt-newer/'
}
},
rollup: {
options: {
format: 'amd',
onwarn: function(warning) {
if (warning.code === 'THIS_IS_UNDEFINED' && grunt.file.match('*/lit-html/directives/async-*.js')) {
// lit-html's Symbol.asyncIterator polyfill in async-{append/replace}.js contains
// a global check for `this`: `(this && this.__asyncValues) || function (o) {`.
// rollup will rewrite that to `function (o) {` and warn about rewriting `this`.
// The rewrite is perfectly ok, the AMD module will act as a singleton, so no
// global window object is needed here. The warning is therefore silenced.
return;
}
console.warn( warning.message );
}
},
'lit-html': {
options: {
preserveModules: true,
plugins: () => [
{
name: 'terser',
renderChunk: code => require('terser').minify(code, grunt.config.get('terser.options'))
}
]
},
files: {
'<%= paths.core %>Public/JavaScript/Contrib/lit-html': [
'node_modules/lit-html/lit-html.js',
'node_modules/lit-html/directives/*.js',
'node_modules/lit-html/lib/*.js',
// omitted, empty
'!node_modules/lit-html/lib/render-options.js',
'!node_modules/lit-html/lib/template-processor.js',
]
}
},
'lit-element': {
options: {
preserveModules: true,
plugins: () => [
{
name: 'terser',
renderChunk: code => require('terser').minify(code, grunt.config.get('terser.options'))
},
{
name: 'externals',
resolveId: (source) => {
if (source === 'lit-html/lit-html.js') {
return {id: 'lit-html', external: true}
}
if (source === 'lit-html/lib/shady-render.js') {
return {id: 'lit-html/lib/shady-render', external: true}
}
return null
}
}
]
},
files: {
'<%= paths.core %>Public/JavaScript/Contrib/lit-element': [
'node_modules/lit-element/lit-element.js',
'node_modules/lit-element/lib/*.js',
]
}
},
},
npmcopy: {
options: {
clean: false,
......@@ -643,6 +709,7 @@ module.exports = function (grunt) {
// Register tasks
grunt.loadNpmTasks('grunt-sass');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-rollup');
grunt.loadNpmTasks('grunt-npmcopy');
grunt.loadNpmTasks('grunt-terser');
grunt.loadNpmTasks('grunt-postcss');
......@@ -707,7 +774,7 @@ module.exports = function (grunt) {
* - yarn install
* - copy some components to a specific destinations because they need to be included via PHP
*/
grunt.registerTask('update', ['exec:yarn-install', 'npmcopy']);
grunt.registerTask('update', ['exec:yarn-install', 'rollup', 'npmcopy']);
/**
* grunt compile-typescript task
......
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
import {render} from 'lit-html';
import {css} from 'lit-element';
import type {TemplateResult} from 'lit-html';
export const renderHTML = (result: TemplateResult): string => {
const anvil = document.createElement('div');
render(result, anvil);
return anvil.innerHTML;
};
......@@ -38,6 +38,7 @@
"grunt-newer": "^1.3.0",
"grunt-npmcopy": "^0.2.0",
"grunt-postcss": "^0.9.0",
"grunt-rollup": "^11.5.0",
"grunt-sass": "^3.1.0",
"grunt-stylelint": "^0.15.0",
"grunt-terser": "^1.0.0",
......@@ -87,6 +88,8 @@
"imagesloaded": "^4.1.4",
"jquery": "^3.5.1",
"jquery-ui": "github:jquery/jquery-ui#1.11.4",
"lit-element": "^2.4",
"lit-html": "^1.3",
"moment": "^2.29.0",
"moment-timezone": "^0.5.31",
"muuri": "^0.9.3",
......
......@@ -4035,6 +4035,13 @@ grunt-postcss@^0.9.0:
diff "^3.0.0"
postcss "^6.0.11"
grunt-rollup@^11.5.0:
version "11.5.0"
resolved "https://registry.yarnpkg.com/grunt-rollup/-/grunt-rollup-11.5.0.tgz#ec1bdda97827054434de21535ac236144f9a50d4"
integrity sha512-Xa/1g0G4HlMIAsJYLZgDEDi8w2jZ5sLpo6XKezJqGdpTGe8qGWcXG7kopiyCUYiXs3LLv58y/DhGIXwbkCAkvQ==
dependencies:
rollup "^2.32.0"
grunt-sass@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/grunt-sass/-/grunt-sass-3.1.0.tgz#a5936cc2a80ec08092d9f31c101dc307d1e4f71c"
......@@ -5439,6 +5446,18 @@ lintspaces@^0.7.0:
minimist "^1.2.5"
rc "^1.2.8"
lit-element@^2.4:
version "2.4.0"
resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-2.4.0.tgz#b22607a037a8fc08f5a80736dddf7f3f5d401452"
integrity sha512-pBGLglxyhq/Prk2H91nA0KByq/hx/wssJBQFiYqXhGDvEnY31PRGYf1RglVzyLeRysu0IHm2K0P196uLLWmwFg==
dependencies:
lit-html "^1.1.1"
lit-html@^1.1.1, lit-html@^1.3:
version "1.3.0"
resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-1.3.0.tgz#c80f3cc5793a6dea6c07172be90a70ab20e56034"
integrity sha512-0Q1bwmaFH9O14vycPHw8C/IeHMk/uSDldVLIefu/kfbTBGIc44KGH6A8p1bDfxUfHdc8q6Ct7kQklWoHgr4t1Q==
livereload-js@^2.3.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.4.0.tgz#447c31cf1ea9ab52fc20db615c5ddf678f78009c"
......@@ -7665,6 +7684,13 @@ rimraf@^3.0.0, rimraf@^3.0.2, rimraf@~3.0.2:
dependencies:
glob "^7.1.3"
rollup@^2.32.0:
version "2.34.2"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.34.2.tgz#fa73e05c64df587e9ed4dc80d7d4e7d4a43f8908"
integrity sha512-mvtQLqu3cNeoctS+kZ09iOPxrc1P1/Bt1z15enuQ5feyKOdM3MJAVFjjsygurDpSWn530xB4AlA83TWIzRstXA==
optionalDependencies:
fsevents "~2.1.2"
run-parallel@^1.1.9:
version "1.1.9"
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679"
......
......@@ -1398,6 +1398,18 @@ class PageRenderer implements SingletonInterface
$requireJsConfig['public']['shim'] = [
'tablesort.dotsep' => ['deps' => ['tablesort']],
];
$requireJsConfig['public']['packages'] = [
[
'name' => 'lit-html',
'location' => $corePath . 'lit-html',
'main' => 'lit-html',
],
[
'name' => 'lit-element',
'location' => $corePath . 'lit-element',
'main' => 'lit-element',
]
];
$requireJsConfig['public']['waitSeconds'] = 30;
$requireJsConfig['public']['typo3BaseUrl'] = false;
$publicPackageNames = ['core', 'frontend', 'backend'];
......@@ -1490,8 +1502,11 @@ class PageRenderer implements SingletonInterface
$requireJsConfig = $this->getRequireJsConfig(static::REQUIREJS_SCOPE_CONFIG);
$requireJsConfig['typo3BaseUrl'] = (string)$uriBuilder->buildUriFromRoute('ajax_core_requirejs');
} else {
// backend request, having backend user logged in
$requireJsConfig = array_replace_recursive(
// Backend request, having backend user logged in.
// Merge public and private require js configuration.
// Use array_merge for 'packages' definitions (scalar array indexes) and
// merge+replace for other, string array based configuration (like 'path' and 'shim').
$requireJsConfig = ArrayUtility::replaceAndAppendScalarValuesRecursive(
$this->publicRequireJsConfig,
$this->requireJsConfig
);
......
.. include:: ../../Includes.txt
=====================================================================================
Feature: #91810 - Introduce lit-html and lit-element as client-side templating engine
=====================================================================================
See :issue:`91810`
Description
===========
To avoid custom jQuery template building a new slim client-side templating
engine `lit-html`_ together with `lit-element_` is introduced.
This templating engine supports conditions, iterations, events, virtual DOM,
data-binding and mutation/change detections in templates.
.. _lit-html: https://lit-html.polymer-project.org/
.. _lit-element: https://lit-element.polymer-project.org/
Impact
======
Individual client-side templates can be processed in JavaScript directly
using modern web technologies like template-strings_ and template-elements_.
.. _template-strings: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
.. _template-elements: https://developer.mozilla.org/de/docs/Web/HTML/Element/template
Rendering is handled by the AMD-modules `lit-html` and `lit-element`.
Please consult the `lit-html` template-reference_ and lit-element-guide_ for more
information.
.. _template-reference: https://lit-html.polymer-project.org/guide/template-reference
.. _lit-element-guide: https://lit-element.polymer-project.org/guide
Examples
========
Variable assignment
-------------------
.. code-block:: ts
import {html, render} from 'lit-html';
const value = 'World';
const target = document.getElementById('target');
render(html`<div>Hello ${value}!</div>`, target);
.. code-block:: html
<div>Hello World!</div>
Unsafe tags would have been encoded (e.g. :html:`<b>World</b>`
as :html:`&lt;b&gt;World&lt;/b&gt;`).
Condition and iteration
-----------------------
.. code-block:: ts
import {html, render} from 'lit-html';
import {classMap} from 'lit-html/directives/class-map.js';
const items = ['a', 'b', 'c']
const classes = { list: true };
const target = document.getElementById('target');
const template = html`
<ul class=${classMap(classes)}">
${items.map((item: string, index: number): string => {
return html`<li>#${index+1}: ${item}</li>`
})}
</ul>
`;
render(template, target);
.. code-block:: html
<ul class="list">
<li>#1: a</li>
<li>#2: b</li>
<li>#3: c</li>
</ul>
The :js:`${...}` literal used in template tags can basically contain any
JavaScript instruction - as long as their result can be casted to `string`
again or is of type `lit-html.TemplateResult`. This allows to
make use of custom conditions as well as iterations:
* condition: :js:`${condition ? thenReturn : elseReturn}`
* iteration: :js:`${array.map((item) => { return item; })}`
Events
------
Events can be bound using the `@` attribute prefix.
.. code-block:: ts
import {html, render} from 'lit-html';
const value = 'World';
const target = document.getElementById('target');
const template = html`
<div @click="${(evt: Event): void => { console.log(value); })}">
Hello ${value}!
</div>
`;
render(template, target);
The result won't look much different than the first example - however the
custom attribute :html:`@click` will be transformed into an according event
listener bound to the element where it has been declared.
Custom HTML elements
------------------
A web component based on the W3C custom elements ("web-components_") specification
can be implemented using `lit-element`.
.. code-block:: ts
import {LitElement, html, customElement, property} from 'lit-element';
@customElement('my-element')
class MyElement extends LitElement {
// Declare observed properties
@property()
value: string = 'awesome';
// Avoid Shadow DOM so global styles apply to the element contents
createRenderRoot(): Element|ShadowRoot {
return this;
}
// Define the element's template
render() {
return html`<p>Hello ${this.value}!</p>`;
}
}
.. code-block:: html
<my-element value="World"></my-element>
This is rendered as:
.. code-block:: html
<my-element value="World">
<p>Hellow world!</p>
</my-element>
.. _web-commponents: https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements
.. index:: Backend, JavaScript, ext:backend
define(["exports"],(function(e){"use strict";
/**
@license
Copyright (c) 2019 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
*/const t=window.ShadowRoot&&(void 0===window.ShadyCSS||window.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,s=Symbol();class n{constructor(e,t){if(t!==s)throw new Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e}get styleSheet(){return void 0===this._styleSheet&&(t?(this._styleSheet=new CSSStyleSheet,this._styleSheet.replaceSync(this.cssText)):this._styleSheet=null),this._styleSheet}toString(){return this.cssText}}e.CSSResult=n,e.css=(e,...t)=>{const o=t.reduce((t,s,o)=>t+(e=>{if(e instanceof n)return e.cssText;if("number"==typeof e)return e;throw new Error(`Value passed to 'css' function must be a 'css' function result: ${e}. Use 'unsafeCSS' to pass non-literal values, but\n take care to ensure page security.`)})(s)+e[o+1],e[0]);return new n(o,s)},e.supportsAdoptingStyleSheets=t,e.unsafeCSS=e=>new n(String(e),s),Object.defineProperty(e,"__esModule",{value:!0})}));
define(["exports"],(function(e){"use strict";
/**
* @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
*/const t=(e,t)=>"method"===t.kind&&t.descriptor&&!("value"in t.descriptor)?Object.assign(Object.assign({},t),{finisher(n){n.createProperty(t.key,e)}}):{kind:"field",key:Symbol(),placement:"own",descriptor:{},initializer(){"function"==typeof t.initializer&&(this[t.key]=t.initializer.call(this))},finisher(n){n.createProperty(t.key,e)}};function n(e){return(n,r)=>void 0!==r?((e,t,n)=>{t.constructor.createProperty(n,e)})(e,n,r):t(e,n)}const r=(e,t,n)=>{Object.defineProperty(t,n,e)},o=(e,t)=>({kind:"method",placement:"prototype",key:t.key,descriptor:e});const i=Element.prototype,s=i.msMatchesSelector||i.webkitMatchesSelector;e.customElement=e=>t=>"function"==typeof t?((e,t)=>(window.customElements.define(e,t),t))(e,t):((e,t)=>{const{kind:n,elements:r}=t;return{kind:n,elements:r,finisher(t){window.customElements.define(e,t)}}})(e,t),e.eventOptions=function(e){return(t,n)=>void 0!==n?((e,t,n)=>{Object.assign(t[n],e)})(e,t,n):((e,t)=>Object.assign(Object.assign({},t),{finisher(n){Object.assign(n.prototype[t.key],e)}}))(e,t)},e.internalProperty=function(e){return n({attribute:!1,hasChanged:null==e?void 0:e.hasChanged})},e.property=n,e.query=function(e,t){return(n,i)=>{const s={get(){return this.renderRoot.querySelector(e)},enumerable:!0,configurable:!0};if(t){const t="symbol"==typeof i?Symbol():"__"+i;s.get=function(){return void 0===this[t]&&(this[t]=this.renderRoot.querySelector(e)),this[t]}}return void 0!==i?r(s,n,i):o(s,n)}},e.queryAll=function(e){return(t,n)=>{const i={get(){return this.renderRoot.querySelectorAll(e)},enumerable:!0,configurable:!0};return void 0!==n?r(i,t,n):o(i,t)}},e.queryAssignedNodes=function(e="",t=!1,n=""){return(i,c)=>{const u={get(){const r="slot"+(e?`[name=${e}]`:":not([name])"),o=this.renderRoot.querySelector(r);let i=o&&o.assignedNodes({flatten:t});return i&&n&&(i=i.filter(e=>e.nodeType===Node.ELEMENT_NODE&&e.matches?e.matches(n):s.call(e,n))),i},enumerable:!0,configurable:!0};return void 0!==c?r(u,i,c):o(u,i)}},e.queryAsync=function(e){return(t,n)=>{const i={async get(){return await this.updateComplete,this.renderRoot.querySelector(e)},enumerable:!0,configurable:!0};return void 0!==n?r(i,t,n):o(i,t)}},Object.defineProperty(e,"__esModule",{value:!0})}));
define(["exports"],(function(t){"use strict";
/**
* @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
*/window.JSCompiler_renameProperty=(t,e)=>t;const e={toAttribute(t,e){switch(e){case Boolean:return t?"":null;case Object:case Array:return null==t?t:JSON.stringify(t)}return t},fromAttribute(t,e){switch(e){case Boolean:return null!==t;case Number:return null===t?null:Number(t);case Object:case Array:return JSON.parse(t)}return t}},r=(t,e)=>e!==t&&(e==e||t==t),s={attribute:!0,type:String,converter:e,reflect:!1,hasChanged:r},i="finalized";class a extends HTMLElement{constructor(){super(),this.initialize()}static get observedAttributes(){this.finalize();const t=[];return this._classProperties.forEach((e,r)=>{const s=this._attributeNameForProperty(r,e);void 0!==s&&(this._attributeToPropertyMap.set(s,r),t.push(s))}),t}static _ensureClassProperties(){if(!this.hasOwnProperty(JSCompiler_renameProperty("_classProperties",this))){this._classProperties=new Map;const t=Object.getPrototypeOf(this)._classProperties;void 0!==t&&t.forEach((t,e)=>this._classProperties.set(e,t))}}static createProperty(t,e=s){if(this._ensureClassProperties(),this._classProperties.set(t,e),e.noAccessor||this.prototype.hasOwnProperty(t))return;const r="symbol"==typeof t?Symbol():"__"+t,i=this.getPropertyDescriptor(t,r,e);void 0!==i&&Object.defineProperty(this.prototype,t,i)}static getPropertyDescriptor(t,e,r){return{get(){return this[e]},set(s){const i=this[t];this[e]=s,this.requestUpdateInternal(t,i,r)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this._classProperties&&this._classProperties.get(t)||s}static finalize(){const t=Object.getPrototypeOf(this);if(t.hasOwnProperty(i)||t.finalize(),this.finalized=!0,this._ensureClassProperties(),this._attributeToPropertyMap=new Map,this.hasOwnProperty(JSCompiler_renameProperty("properties",this))){const t=this.properties,e=[...Object.getOwnPropertyNames(t),..."function"==typeof Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(t):[]];for(const r of e)this.createProperty(r,t[r])}}static _attributeNameForProperty(t,e){const r=e.attribute;return!1===r?void 0:"string"==typeof r?r:"string"==typeof t?t.toLowerCase():void 0}static _valueHasChanged(t,e,s=r){return s(t,e)}static _propertyValueFromAttribute(t,r){const s=r.type,i=r.converter||e,a="function"==typeof i?i:i.fromAttribute;return a?a(t,s):t}static _propertyValueToAttribute(t,r){if(void 0===r.reflect)return;const s=r.type,i=r.converter;return(i&&i.toAttribute||e.toAttribute)(t,s)}initialize(){this._updateState=0,this._updatePromise=new Promise(t=>this._enableUpdatingResolver=t),this._changedProperties=new Map,this._saveInstanceProperties(),this.requestUpdateInternal()}_saveInstanceProperties(){this.constructor._classProperties.forEach((t,e)=>{if(this.hasOwnProperty(e)){const t=this[e];delete this[e],this._instanceProperties||(this._instanceProperties=new Map),this._instanceProperties.set(e,t)}})}_applyInstanceProperties(){this._instanceProperties.forEach((t,e)=>this[e]=t),this._instanceProperties=void 0}connectedCallback(){this.enableUpdating()}enableUpdating(){void 0!==this._enableUpdatingResolver&&(this._enableUpdatingResolver(),this._enableUpdatingResolver=void 0)}disconnectedCallback(){}attributeChangedCallback(t,e,r){e!==r&&this._attributeToProperty(t,r)}_propertyToAttribute(t,e,r=s){const i=this.constructor,a=i._attributeNameForProperty(t,r);if(void 0!==a){const t=i._propertyValueToAttribute(e,r);if(void 0===t)return;this._updateState=8|this._updateState,null==t?this.removeAttribute(a):this.setAttribute(a,t),this._updateState=-9&this._updateState}}_attributeToProperty(t,e){if(8&this._updateState)return;const r=this.constructor,s=r._attributeToPropertyMap.get(t);if(void 0!==s){const t=r.getPropertyOptions(s);this._updateState=16|this._updateState,this[s]=r._propertyValueFromAttribute(e,t),this._updateState=-17&this._updateState}}requestUpdateInternal(t,e,r){let s=!0;if(void 0!==t){const i=this.constructor;r=r||i.getPropertyOptions(t),i._valueHasChanged(this[t],e,r.hasChanged)?(this._changedProperties.has(t)||this._changedProperties.set(t,e),!0!==r.reflect||16&this._updateState||(void 0===this._reflectingProperties&&(this._reflectingProperties=new Map),this._reflectingProperties.set(t,r))):s=!1}!this._hasRequestedUpdate&&s&&(this._updatePromise=this._enqueueUpdate())}requestUpdate(t,e){return this.requestUpdateInternal(t,e),this.updateComplete}async _enqueueUpdate(){this._updateState=4|this._updateState;try{await this._updatePromise}catch(t){}const t=this.performUpdate();return null!=t&&await t,!this._hasRequestedUpdate}get _hasRequestedUpdate(){return 4&this._updateState}get hasUpdated(){return 1&this._updateState}performUpdate(){if(!this._hasRequestedUpdate)return;this._instanceProperties&&this._applyInstanceProperties();let t=!1;const e=this._changedProperties;try{t=this.shouldUpdate(e),t?this.update(e):this._markUpdated()}catch(e){throw t=!1,this._markUpdated(),e}t&&(1&this._updateState||(this._updateState=1|this._updateState,this.firstUpdated(e)),this.updated(e))}_markUpdated(){this._changedProperties=new Map,this._updateState=-5&this._updateState}get updateComplete(){return this._getUpdateComplete()}_getUpdateComplete(){return this._updatePromise}shouldUpdate(t){return!0}update(t){void 0!==this._reflectingProperties&&this._reflectingProperties.size>0&&(this._reflectingProperties.forEach((t,e)=>this._propertyToAttribute(e,this[e],t)),this._reflectingProperties=void 0),this._markUpdated()}updated(t){}firstUpdated(t){}}a.finalized=!0,t.UpdatingElement=a,t.defaultConverter=e,t.notEqual=r,Object.defineProperty(t,"__esModule",{value:!0})}));
define(["exports","lit-html/lib/shady-render","./lib/updating-element","./lib/decorators","lit-html","./lib/css-tag"],(function(e,t,s,n,r,o){"use strict";
/**
* @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
*/(window.litElementVersions||(window.litElementVersions=[])).push("2.4.0");const i={};class l extends s.UpdatingElement{static getStyles(){return this.styles}static _getUniqueStyles(){if(this.hasOwnProperty(JSCompiler_renameProperty("_styles",this)))return;const e=this.getStyles();if(Array.isArray(e)){const t=(e,s)=>e.reduceRight((e,s)=>Array.isArray(s)?t(s,e):(e.add(s),e),s),s=t(e,new Set),n=[];s.forEach(e=>n.unshift(e)),this._styles=n}else this._styles=void 0===e?[]:[e];this._styles=this._styles.map(e=>{if(e instanceof CSSStyleSheet&&!o.supportsAdoptingStyleSheets){const t=Array.prototype.slice.call(e.cssRules).reduce((e,t)=>e+t.cssText,"");return o.unsafeCSS(t)}return e})}initialize(){super.initialize(),this.constructor._getUniqueStyles(),this.renderRoot=this.createRenderRoot(),window.ShadowRoot&&this.renderRoot instanceof window.ShadowRoot&&this.adoptStyles()}createRenderRoot(){return this.attachShadow({mode:"open"})}adoptStyles(){const e=this.constructor._styles;0!==e.length&&(void 0===window.ShadyCSS||window.ShadyCSS.nativeShadow?o.supportsAdoptingStyleSheets?this.renderRoot.adoptedStyleSheets=e.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet):this._needsShimAdoptedStyleSheets=!0:window.ShadyCSS.ScopingShim.prepareAdoptedCssText(e.map(e=>e.cssText),this.localName))}connectedCallback(){super.connectedCallback(),this.hasUpdated&&void 0!==window.ShadyCSS&&window.ShadyCSS.styleElement(this)}update(e){const t=this.render();super.update(e),t!==i&&this.constructor.render(t,this.renderRoot,{scopeName:this.localName,eventContext:this}),this._needsShimAdoptedStyleSheets&&(this._needsShimAdoptedStyleSheets=!1,this.constructor._styles.forEach(e=>{const t=document.createElement("style");t.textContent=e.cssText,this.renderRoot.appendChild(t)}))}render(){return i}}l.finalized=!0,l.render=t.render,e.UpdatingElement=s.UpdatingElement,e.defaultConverter=s.defaultConverter,e.notEqual=s.notEqual,e.customElement=n.customElement,e.eventOptions=n.eventOptions,e.internalProperty=n.internalProperty,e.property=n.property,e.query=n.query,e.queryAll=n.queryAll,e.queryAssignedNodes=n.queryAssignedNodes,e.queryAsync=n.queryAsync,Object.defineProperty(e,"SVGTemplateResult",{enumerable:!0,get:function(){return r.SVGTemplateResult}}),Object.defineProperty(e,"TemplateResult",{enumerable:!0,get:function(){return r.TemplateResult}}),Object.defineProperty(e,"html",{enumerable:!0,get:function(){return r.html}}),Object.defineProperty(e,"svg",{enumerable:!0,get:function(){return r.svg}}),e.CSSResult=o.CSSResult,e.css=o.css,e.supportsAdoptingStyleSheets=o.supportsAdoptingStyleSheets,e.unsafeCSS=o.unsafeCSS,e.LitElement=l,Object.defineProperty(e,"__esModule",{value:!0})}));
define(["exports","../lib/directive","../lib/template","../lib/parts","../lit-html"],(function(e,t,r,n,o){"use strict";
/**
* @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
*/var a=function(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t,r=e[Symbol.asyncIterator];return r?r.call(e):(e="function"==typeof __values?__values(e):e[Symbol.iterator](),t={},n("next"),n("throw"),n("return"),t[Symbol.asyncIterator]=function(){return this},t);function n(r){t[r]=e[r]&&function(t){return new Promise((function(n,o){(function(e,t,r,n){Promise.resolve(n).then((function(t){e({value:t,done:r})}),t)})(n,o,(t=e[r](t)).done,t.value)}))}}};const i=t.directive((e,t)=>async o=>{var i,l;if(!(o instanceof n.NodePart))throw new Error("asyncAppend can only be used in text bindings");if(e===o.value)return;let c;o.value=e;let d=0;try{for(var s,u=a(e);!(s=await u.next()).done;){let a=s.value;if(o.value!==e)break;0===d&&o.clear(),void 0!==t&&(a=t(a,d));let i=o.startNode;void 0!==c&&(i=r.createMarker(),c.endNode=i,o.endNode.parentNode.insertBefore(i,o.endNode)),c=new n.NodePart(o.options),c.insertAfterNode(i),c.setValue(a),c.commit(),d++}}catch(e){i={error:e}}finally{try{s&&!s.done&&(l=u.return)&&await l.call(u)}finally{if(i)throw i.error}}});e.asyncAppend=i,Object.defineProperty(e,"__esModule",{value:!0})}));
define(["exports","../lib/directive","../lib/parts","../lit-html"],(function(e,t,n,r){"use strict";
/**
* @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
*/var o=function(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t,n=e[Symbol.asyncIterator];return n?n.call(e):(e="function"==typeof __values?__values(e):e[Symbol.iterator](),t={},r("next"),r("throw"),r("return"),t[Symbol.asyncIterator]=function(){return this},t);function r(n){t[n]=e[n]&&function(t){return new Promise((function(r,o){(function(e,t,n,r){Promise.resolve(r).then((function(t){e({value:t,done:n})}),t)})(r,o,(t=e[n](t)).done,t.value)}))}}};const a=t.directive((e,t)=>async r=>{var a,i;if(!(r instanceof n.NodePart))throw new Error("asyncReplace can only be used in text bindings");if(e===r.value)return;const l=new n.NodePart(r.options);r.value=e;let c=0;try{for(var u,s=o(e);!(u=await s.next()).done;){let n=u.value;if(r.value!==e)break;0===c&&(r.clear(),l.appendIntoPart(r)),void 0!==t&&(n=t(n,c)),l.setValue(n),l.commit(),c++}}catch(e){a={error:e}}finally{try{u&&!u.done&&(i=s.return)&&await i.call(s)}finally{if(a)throw a.error}}});e.asyncReplace=a,Object.defineProperty(e,"__esModule",{value:!0})}));
define(["exports","../lib/directive","../lib/dom","../lib/template-instance","../lib/template-result","../lib/parts","../lit-html"],(function(e,t,n,a,i,o,s){"use strict";
/**
* @license
* Copyright (c) 2018 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
*/const l=new WeakMap,c=t.directive(e=>t=>{if(!(t instanceof o.NodePart))throw new Error("cache can only be used in text bindings");let s=l.get(t);void 0===s&&(s=new WeakMap,l.set(t,s));const c=t.value;if(c instanceof a.TemplateInstance){if(e instanceof i.TemplateResult&&c.template===t.options.templateFactory(e))return void t.setValue(e);{let e=s.get(c.template);void 0===e&&(e={instance:c,nodes:document.createDocumentFragment()},s.set(c.template,e)),n.reparentNodes(e.nodes,t.startNode.nextSibling,t.endNode)}}if(e instanceof i.TemplateResult){const n=t.options.templateFactory(e),a=s.get(n);void 0!==a&&(t.setValue(a.nodes),t.commit(),t.value=a.instance)}t.setValue(e)});e.cache=c,Object.defineProperty(e,"__esModule",{value:!0})}));
define(["exports","../lib/directive","../lib/parts","../lit-html"],(function(t,e,s,i){"use strict";
/**
* @license
* Copyright (c) 2018 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
*/class c{constructor(t){this.classes=new Set,this.changed=!1,this.element=t;const e=(t.getAttribute("class")||"").split(/\s+/);for(const t of e)this.classes.add(t)}add(t){this.classes.add(t),this.changed=!0}remove(t){this.classes.delete(t),this.changed=!0}commit(){if(this.changed){let t="";this.classes.forEach(e=>t+=e+" "),this.element.setAttribute("class",t)}}}const a=new WeakMap,n=e.directive(t=>e=>{if(!(e instanceof s.AttributePart)||e instanceof s.PropertyPart||"class"!==e.committer.name||e.committer.parts.length>1)throw new Error("The `classMap` directive must be used in the `class` attribute and must be the only part in the attribute.");const{committer:i}=e,{element:n}=i;let o=a.get(e);void 0===o&&(n.setAttribute("class",i.strings.join(" ")),a.set(e,o=new Set));const r=n.classList||new c(n);o.forEach(e=>{e in t||(r.remove(e),o.delete(e))});for(const e in t){const s=t[e];s!=o.has(e)&&(s?(r.add(e),o.add(e)):(r.remove(e),o.delete(e)))}"function"==typeof r.commit&&r.commit()});t.classMap=n,Object.defineProperty(t,"__esModule",{value:!0})}));
define(["exports","../lib/directive","../lit-html"],(function(e,r,t){"use strict";
/**
* @license
* Copyright (c) 2018 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