From 83b4d5286fe4acec98cdfa0aa85a1ba53fae71c7 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Thu, 7 Nov 2019 07:23:50 -0600 Subject: [PATCH] add devcontainer and cleanup build --- .devcontainer/configuration.yaml | 4 + .devcontainer/devcontainer.json | 32 + .devcontainer/ui-lovelace.yaml | 41 + .eslintrc.js | 16 + .eslintrc.yaml | 18 - .gitignore | 3 +- .prettierrc.js | 7 + babel.config.js | 6 - dist/radial-menu.js | 2944 +----------------------------- package.json | 92 +- rollup.config.dev.js | 30 + rollup.config.js | 19 +- src/action-handler-directive.ts | 126 +- src/const.ts | 2 +- src/radial-menu.ts | 136 +- src/types.ts | 16 +- tsconfig.json | 2 +- yarn.lock | 181 +- 18 files changed, 523 insertions(+), 3152 deletions(-) create mode 100644 .devcontainer/configuration.yaml create mode 100644 .devcontainer/devcontainer.json create mode 100644 .devcontainer/ui-lovelace.yaml create mode 100644 .eslintrc.js delete mode 100644 .eslintrc.yaml create mode 100644 .prettierrc.js delete mode 100644 babel.config.js create mode 100644 rollup.config.dev.js diff --git a/.devcontainer/configuration.yaml b/.devcontainer/configuration.yaml new file mode 100644 index 0000000..9b01ded --- /dev/null +++ b/.devcontainer/configuration.yaml @@ -0,0 +1,4 @@ +default_config: +lovelace: + mode: yaml +demo: \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..6d4e99a --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,32 @@ +// See https://aka.ms/vscode-remote/devcontainer.json for format details. +{ + "name": "Radial Menu Element Development", + "image": "ludeeus/devcontainer:monster-stable", + "context": "..", + "appPort": ["5000:5000", "9123:8123"], + "postCreateCommand": "npm install", + "runArgs": [ + "-v", + "${env:HOME}${env:USERPROFILE}/.ssh:/tmp/.ssh" // This is added so you can push from inside the container + ], + "extensions": [ + "github.vscode-pull-request-github", + "eamodio.gitlens", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "bierner.lit-html", + "runem.lit-plugin", + "auchenberg.vscode-browser-preview", + "davidanson.vscode-markdownlint", + "redhat.vscode-yaml" + ], + "settings": { + "files.eol": "\n", + "editor.tabSize": 4, + "terminal.integrated.shell.linux": "/bin/bash", + "editor.formatOnPaste": false, + "editor.formatOnSave": true, + "editor.formatOnType": true, + "files.trimTrailingWhitespace": true + } +} diff --git a/.devcontainer/ui-lovelace.yaml b/.devcontainer/ui-lovelace.yaml new file mode 100644 index 0000000..476f3b6 --- /dev/null +++ b/.devcontainer/ui-lovelace.yaml @@ -0,0 +1,41 @@ +resources: + - url: http://127.0.0.1:5000/radial-menu.js + type: module +views: + - cards: + - type: custom:radial-menu + icon: mdi:home + name: Home + default_open: true + default_dismiss: false + hold_action: + action: url + url: https://www.home-assistant.io + items: + - entity: light.bed_light + icon: mdi:flash + name: Bedroom Light + tap_action: + action: toggle + haptic: true + hold_action: + action: more-info + - entity: alarm_control_panel.ha_alarm + icon: mdi:alarm-light + name: Alarm Panel + tap_action: + action: more-info + - icon: mdi:alarm + name: Timer + tap_action: + action: call-service + service: timer.start + service_data: + entity_id: timer.laundry + haptic: true + hold_action: + action: call-service + service: timer.pause + service_data: + entity_id: timer.laundry + haptic: true diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..fc69b8b --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,16 @@ +module.exports = { + parser: '@typescript-eslint/parser', // Specifies the ESLint parser + extends: [ + 'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin + 'prettier/@typescript-eslint', // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier + 'plugin:prettier/recommended', // Enables eslint-plugin-prettier and displays prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array. + ], + parserOptions: { + ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features + sourceType: 'module', // Allows for the use of imports + experimentalDecorators: true, + }, + rules: { + "@typescript-eslint/camelcase": 0 + } +}; diff --git a/.eslintrc.yaml b/.eslintrc.yaml deleted file mode 100644 index 6b60ded..0000000 --- a/.eslintrc.yaml +++ /dev/null @@ -1,18 +0,0 @@ -extends: airbnb-base -parser: "@typescript-eslint/parser" -rules: - no-else-return: 0 - no-underscore-dangle: 0 - nonblock-statement-body-position: 0 - curly: 0 - no-return-assign: 0 - consistent-return: 0 - no-mixed-operators: 0 - class-methods-use-this: 0 - no-nested-ternary: 0 - camelcase: 0 - no-unused-vars: 0 -globals: - window: true - Event: true - customElements: true diff --git a/.gitignore b/.gitignore index e8ecf85..acfea94 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /node_modules/ -.rpt2_cache/ \ No newline at end of file +/.rpt2_cache/ +package-lock.json \ No newline at end of file diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000..4121004 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,7 @@ +module.exports = { + semi: true, + trailingComma: 'all', + singleQuote: true, + printWidth: 120, + tabWidth: 2, +}; diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index bc267c0..0000000 --- a/babel.config.js +++ /dev/null @@ -1,6 +0,0 @@ -const plugins = [ - '@babel/plugin-proposal-class-properties', - ['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: true }], -]; - -module.exports = { plugins }; \ No newline at end of file diff --git a/dist/radial-menu.js b/dist/radial-menu.js index a5c02a9..4b05d8d 100644 --- a/dist/radial-menu.js +++ b/dist/radial-menu.js @@ -1,25 +1,18 @@ -/*! ***************************************************************************** -Copyright (c) Microsoft Corporation. All rights reserved. -Licensed under the Apache License, Version 2.0 (the "License"); you may not use -this file except in compliance with the License. You may obtain a copy of the -License at http://www.apache.org/licenses/LICENSE-2.0 - -THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED -WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -MERCHANTABLITY OR NON-INFRINGEMENT. - -See the Apache Version 2.0 License for specific language governing permissions -and limitations under the License. -***************************************************************************** */ - -function __decorate(decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; -} - +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ +function t(t,e,n,i){var s,o=arguments.length,r=o<3?e:null===i?i=Object.getOwnPropertyDescriptor(e,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(t,e,n,i);else for(var a=t.length-1;a>=0;a--)(s=t[a])&&(r=(o<3?s(r):o>3?s(e,n,r):s(e,n))||r);return o>3&&r&&Object.defineProperty(e,n,r),r /** * @license * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. @@ -32,38 +25,7 @@ function __decorate(decorators, target, key, desc) { * 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 directives = new WeakMap(); -/** - * Brands a function as a directive so that lit-html will call the function - * during template rendering, rather than passing as a value. - * - * @param f The directive factory function. Must be a function that returns a - * function of the signature `(part: Part) => void`. The returned function will - * be called with the part object - * - * @example - * - * ``` - * import {directive, html} from 'lit-html'; - * - * const immutable = directive((v) => (part) => { - * if (part.value !== v) { - * part.setValue(v) - * } - * }); - * ``` - */ -// tslint:disable-next-line:no-any -const directive = (f) => ((...args) => { - const d = f(...args); - directives.set(d, true); - return d; -}); -const isDirective = (o) => { - return typeof o === 'function' && directives.has(o); -}; - + */}const e=new WeakMap,n=t=>"function"==typeof t&&e.has(t),i=void 0!==window.customElements&&void 0!==window.customElements.polyfillWrapFlushCallback,s=(t,e,n=null)=>{for(;e!==n;){const n=e.nextSibling;t.removeChild(e),e=n}},o={},r={},a=`{{lit-${String(Math.random()).slice(2)}}}`,c=`\x3c!--${a}--\x3e`,l=new RegExp(`${a}|${c}`),d="$lit$";class u{constructor(t,e){this.parts=[],this.element=e;const n=[],i=[],s=document.createTreeWalker(e.content,133,null,!1);let o=0,r=-1,c=0;const{strings:u,values:{length:p}}=t;for(;c0;){const e=u[c],n=f.exec(e)[2],i=n.toLowerCase()+d,s=t.getAttribute(i);t.removeAttribute(i);const o=s.split(l);this.parts.push({type:"attribute",index:r,name:n,strings:o}),c+=o.length-1}}"TEMPLATE"===t.tagName&&(i.push(t),s.currentNode=t.content)}else if(3===t.nodeType){const e=t.data;if(e.indexOf(a)>=0){const i=t.parentNode,s=e.split(l),o=s.length-1;for(let e=0;e{const n=t.length-e.length;return n>=0&&t.slice(n)===e},p=t=>-1!==t.index,m=()=>document.createComment(""),f=/([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F "'>=/]+)([ \x09\x0a\x0c\x0d]*=[ \x09\x0a\x0c\x0d]*(?:[^ \x09\x0a\x0c\x0d"'`<>=]*|"[^"]*|'[^']*))$/; /** * @license * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. @@ -77,48 +39,7 @@ const isDirective = (o) => { * subject to an additional IP rights grant found at * http://polymer.github.io/PATENTS.txt */ -/** - * True if the custom elements polyfill is in use. - */ -const isCEPolyfill = window.customElements !== undefined && - window.customElements.polyfillWrapFlushCallback !== - undefined; -/** - * Removes nodes, starting from `startNode` (inclusive) to `endNode` - * (exclusive), from `container`. - */ -const removeNodes = (container, startNode, endNode = null) => { - let node = startNode; - while (node !== endNode) { - const n = node.nextSibling; - container.removeChild(node); - node = n; - } -}; - -/** - * @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 - */ -/** - * A sentinel value that signals that a value was handled by a directive and - * should not be written to the DOM. - */ -const noChange = {}; -/** - * A sentinel value that signals a NodePart to fully clear its content. - */ -const nothing = {}; - +class g{constructor(t,e,n){this.__parts=[],this.template=t,this.processor=e,this.options=n}update(t){let e=0;for(const n of this.__parts)void 0!==n&&n.setValue(t[e]),e++;for(const t of this.__parts)void 0!==t&&t.commit()}_clone(){const t=i?this.template.element.content.cloneNode(!0):document.importNode(this.template.element.content,!0),e=[],n=this.template.parts,s=document.createTreeWalker(t,133,null,!1);let o,r=0,a=0,c=s.nextNode();for(;r`; -const markerRegex = new RegExp(`${marker}|${nodeMarker}`); -/** - * Suffix appended to all bound attribute names. - */ -const boundAttributeSuffix = '$lit$'; -/** - * An updateable Template that tracks the location of dynamic parts. - */ -class Template { - constructor(result, element) { - this.parts = []; - this.element = element; - let index = -1; - let partIndex = 0; - const nodesToRemove = []; - const _prepareTemplate = (template) => { - const content = template.content; - // Edge needs all 4 parameters present; IE11 needs 3rd parameter to be - // null - const walker = document.createTreeWalker(content, 133 /* NodeFilter.SHOW_{ELEMENT|COMMENT|TEXT} */, null, false); - // Keeps track of the last index associated with a part. We try to delete - // unnecessary nodes, but we never want to associate two different parts - // to the same index. They must have a constant node between. - let lastPartIndex = 0; - while (walker.nextNode()) { - index++; - const node = walker.currentNode; - if (node.nodeType === 1 /* Node.ELEMENT_NODE */) { - if (node.hasAttributes()) { - const attributes = node.attributes; - // Per - // https://developer.mozilla.org/en-US/docs/Web/API/NamedNodeMap, - // attributes are not guaranteed to be returned in document order. - // In particular, Edge/IE can return them out of order, so we cannot - // assume a correspondance between part index and attribute index. - let count = 0; - for (let i = 0; i < attributes.length; i++) { - if (attributes[i].value.indexOf(marker) >= 0) { - count++; - } - } - while (count-- > 0) { - // Get the template literal section leading up to the first - // expression in this attribute - const stringForPart = result.strings[partIndex]; - // Find the attribute name - const name = lastAttributeNameRegex.exec(stringForPart)[2]; - // Find the corresponding attribute - // All bound attributes have had a suffix added in - // TemplateResult#getHTML to opt out of special attribute - // handling. To look up the attribute value we also need to add - // the suffix. - const attributeLookupName = name.toLowerCase() + boundAttributeSuffix; - const attributeValue = node.getAttribute(attributeLookupName); - const strings = attributeValue.split(markerRegex); - this.parts.push({ type: 'attribute', index, name, strings }); - node.removeAttribute(attributeLookupName); - partIndex += strings.length - 1; - } - } - if (node.tagName === 'TEMPLATE') { - _prepareTemplate(node); - } - } - else if (node.nodeType === 3 /* Node.TEXT_NODE */) { - const data = node.data; - if (data.indexOf(marker) >= 0) { - const parent = node.parentNode; - const strings = data.split(markerRegex); - const lastIndex = strings.length - 1; - // Generate a new text node for each literal section - // These nodes are also used as the markers for node parts - for (let i = 0; i < lastIndex; i++) { - parent.insertBefore((strings[i] === '') ? createMarker() : - document.createTextNode(strings[i]), node); - this.parts.push({ type: 'node', index: ++index }); - } - // If there's no text, we must insert a comment to mark our place. - // Else, we can trust it will stick around after cloning. - if (strings[lastIndex] === '') { - parent.insertBefore(createMarker(), node); - nodesToRemove.push(node); - } - else { - node.data = strings[lastIndex]; - } - // We have a part for each match found - partIndex += lastIndex; - } - } - else if (node.nodeType === 8 /* Node.COMMENT_NODE */) { - if (node.data === marker) { - const parent = node.parentNode; - // Add a new marker node to be the startNode of the Part if any of - // the following are true: - // * We don't have a previousSibling - // * The previousSibling is already the start of a previous part - if (node.previousSibling === null || index === lastPartIndex) { - index++; - parent.insertBefore(createMarker(), node); - } - lastPartIndex = index; - this.parts.push({ type: 'node', index }); - // If we don't have a nextSibling, keep this node so we have an end. - // Else, we can remove it to save future costs. - if (node.nextSibling === null) { - node.data = ''; - } - else { - nodesToRemove.push(node); - index--; - } - partIndex++; - } - else { - let i = -1; - while ((i = node.data.indexOf(marker, i + 1)) !== - -1) { - // Comment node has a binding marker inside, make an inactive part - // The binding won't work, but subsequent bindings will - // TODO (justinfagnani): consider whether it's even worth it to - // make bindings in comments work - this.parts.push({ type: 'node', index: -1 }); - } - } - } - } - }; - _prepareTemplate(element); - // Remove text binding nodes after the walk to not disturb the TreeWalker - for (const n of nodesToRemove) { - n.parentNode.removeChild(n); - } - } -} -const isTemplatePartActive = (part) => part.index !== -1; -// Allows `document.createComment('')` to be renamed for a -// small manual size-savings. -const createMarker = () => document.createComment(''); -/** - * This regex extracts the attribute name preceding an attribute-position - * expression. It does this by matching the syntax allowed for attributes - * against the string literal directly preceding the expression, assuming that - * the expression is in an attribute-value position. - * - * See attributes in the HTML spec: - * https://www.w3.org/TR/html5/syntax.html#attributes-0 - * - * "\0-\x1F\x7F-\x9F" are Unicode control characters - * - * " \x09\x0a\x0c\x0d" are HTML space characters: - * https://www.w3.org/TR/html5/infrastructure.html#space-character - * - * So an attribute is: - * * The name: any character except a control character, space character, ('), - * ("), ">", "=", or "/" - * * Followed by zero or more space characters - * * Followed by "=" - * * Followed by zero or more space characters - * * Followed by: - * * Any character except space, ('), ("), "<", ">", "=", (`), or - * * (") then any non-("), or - * * (') then any non-(') - */ -const lastAttributeNameRegex = /([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F \x09\x0a\x0c\x0d"'>=/]+)([ \x09\x0a\x0c\x0d]*=[ \x09\x0a\x0c\x0d]*(?:[^ \x09\x0a\x0c\x0d"'`<>=]*|"[^"]*|'[^']*))$/; - + */const _=` ${a} `;class y{constructor(t,e,n,i){this.strings=t,this.values=e,this.type=n,this.processor=i}getHTML(){const t=this.strings.length-1;let e="",n=!1;for(let i=0;i-1||n)&&-1===t.indexOf("--\x3e",s+1);const o=f.exec(t);e+=null===o?t+(n?_:c):t.substr(0,o.index)+o[1]+o[2]+d+o[3]+a}return e+=this.strings[t]}getTemplateElement(){const t=document.createElement("template");return t.innerHTML=this.getHTML(),t}} /** * @license * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. @@ -320,91 +65,7 @@ const lastAttributeNameRegex = /([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F \x09\x0 * 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 - */ -/** - * An instance of a `Template` that can be attached to the DOM and updated - * with new values. - */ -class TemplateInstance { - constructor(template, processor, options) { - this._parts = []; - this.template = template; - this.processor = processor; - this.options = options; - } - update(values) { - let i = 0; - for (const part of this._parts) { - if (part !== undefined) { - part.setValue(values[i]); - } - i++; - } - for (const part of this._parts) { - if (part !== undefined) { - part.commit(); - } - } - } - _clone() { - // When using the Custom Elements polyfill, clone the node, rather than - // importing it, to keep the fragment in the template's document. This - // leaves the fragment inert so custom elements won't upgrade and - // potentially modify their contents by creating a polyfilled ShadowRoot - // while we traverse the tree. - const fragment = isCEPolyfill ? - this.template.element.content.cloneNode(true) : - document.importNode(this.template.element.content, true); - const parts = this.template.parts; - let partIndex = 0; - let nodeIndex = 0; - const _prepareInstance = (fragment) => { - // Edge needs all 4 parameters present; IE11 needs 3rd parameter to be - // null - const walker = document.createTreeWalker(fragment, 133 /* NodeFilter.SHOW_{ELEMENT|COMMENT|TEXT} */, null, false); - let node = walker.nextNode(); - // Loop through all the nodes and parts of a template - while (partIndex < parts.length && node !== null) { - const part = parts[partIndex]; - // Consecutive Parts may have the same node index, in the case of - // multiple bound attributes on an element. So each iteration we either - // increment the nodeIndex, if we aren't on a node with a part, or the - // partIndex if we are. By not incrementing the nodeIndex when we find a - // part, we allow for the next part to be associated with the current - // node if neccessasry. - if (!isTemplatePartActive(part)) { - this._parts.push(undefined); - partIndex++; - } - else if (nodeIndex === part.index) { - if (part.type === 'node') { - const part = this.processor.handleTextExpression(this.options); - part.insertAfterNode(node.previousSibling); - this._parts.push(part); - } - else { - this._parts.push(...this.processor.handleAttributeExpressions(node, part.name, part.strings, this.options)); - } - partIndex++; - } - else { - nodeIndex++; - if (node.nodeName === 'TEMPLATE') { - _prepareInstance(node.content); - } - node = walker.nextNode(); - } - } - }; - _prepareInstance(fragment); - if (isCEPolyfill) { - document.adoptNode(fragment); - customElements.upgrade(fragment); - } - return fragment; - } -} - + */const v=t=>null===t||!("object"==typeof t||"function"==typeof t),b=t=>Array.isArray(t)||!(!t||!t[Symbol.iterator]);class w{constructor(t,e,n){this.dirty=!0,this.element=t,this.name=e,this.strings=n,this.parts=[];for(let t=0;tthis.handleEvent(t)}setValue(t){this.__pendingValue=t}commit(){for(;n(this.__pendingValue);){const t=this.__pendingValue;this.__pendingValue=o,t(this)}if(this.__pendingValue===o)return;const t=this.__pendingValue,e=this.value,i=null==t||null!=e&&(t.capture!==e.capture||t.once!==e.once||t.passive!==e.passive),s=null!=t&&(null==e||i);i&&this.element.removeEventListener(this.eventName,this.__boundHandleEvent,this.__options),s&&(this.__options=T(t),this.element.addEventListener(this.eventName,this.__boundHandleEvent,this.__options)),this.value=t,this.__pendingValue=o}handleEvent(t){"function"==typeof this.value?this.value.call(this.eventContext||this.element,t):this.value.handleEvent(t)}}const T=t=>t&&(N?{capture:t.capture,passive:t.passive,once:t.once}:t.capture); /** * @license * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. @@ -417,58 +78,7 @@ class TemplateInstance { * 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 - */ -/** - * The return type of `html`, which holds a Template and the values from - * interpolated expressions. - */ -class TemplateResult { - constructor(strings, values, type, processor) { - this.strings = strings; - this.values = values; - this.type = type; - this.processor = processor; - } - /** - * Returns a string of HTML used to create a `