diff --git a/README.md b/README.md
index b581654..8f2c4dc 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,18 @@
-# Slider button card by [@mattieha](https://www.github.com/mattieha)
+# Slider button scard by [@mattieha](https://www.github.com/mattieha)
+## Forked and maintained by [@lizsugar](https://www.github.com/lizsugar)
[![GitHub Release][releases-shield]][releases]
[](https://github.com/custom-components/hacs)
A button card with integrated slider for `light, switch, fan, cover, input_boolean, media_player, climate, lock` entities.
+Additions on top of main card:
+- `automation, binary_sensor, sensor, input_number, script, scene` entities supported
+- Slider moves based on relative position of mouse or finger, not absolute
+- Support for tap action on a card independent of slider enabled or disabled
+- Option to show entity attribute
+- Visual changes to look more like Google Home's control cards
+- Display fan speeds correctly - from [@rohankapoorcom](https://github.com/rohankapoorcom).
+
![Preview][preview]
![Preview 2][preview-2]
@@ -44,12 +53,20 @@ A button card with integrated slider for `light, switch, fan, cover, input_boole
## Installation
### HACS
-This card is available in [HACS][hacs] (Home Assistant Community Store).
+The original card is available in [HACS][hacs] (Home Assistant Community Store).
Just search for `Slider Button Card` in Frontend tab.
+**This** fork of it is not. Follow these steps to manually add it to HACS:
+
+1. Open HACS in your Home Assistant
+2. Click on _Frontend_ → _three-dot menu in top right_ → _Custom Repositories_
+3. Add the URL of this repository to the _Repository_ field and select "Lovelace" from the _Category_ dropdown.
+4. Press _Add_
+
+
### Manual
-1. Download `slider-button-card.js` file from the [latest-release].
+1. Download `slider-button-card.js` file from [main branch](https://github.com/lizsugar/slider-button-card/blob/main/dist/slider-button-card.js).
2. Put `slider-button-card.js` file into your `config/www` folder.
3. Go to _Configuration_ → _Lovelace Dashboards_ → _Resources_ → Click Plus button → Set _Url_ as `/local/slider-button-card.js` → Set _Resource type_ as `JavaScript Module`.
4. Add `custom:slider-button-card` to Lovelace UI as any other card (using either editor or YAML configuration).
@@ -68,40 +85,44 @@ Slider Button Card supports Lovelace's Visual Editor.
### Options
-| Name | Type | Requirement | Description | Default |
-| ----------------- | ------- | ------------ | ------------------------------------------- | ------------------- |
-| type | string | **Required** | `custom:slider-button-card` |
-| entity | string | **Required** | HA entity ID from domain `light, switch, fan, cover, input_boolean, media_player, climate, lock` | |
-| name | string | **Optional** | Name | `entity.friendly_name` |
-| show_name | boolean | **Optional** | Show name | `true` |
-| show_state | boolean | **Optional** | Show state | `true` |
-| compact | boolean | **Optional** | Compact mode, display name and state inline with icon. Useful for full width cards. | `false` |
-| icon | object | **Optional** | [Icon options](#icon-options) | |
-| slider | object | **Optional** | [Slider options](#slider-options) | |
-| action_button | object | **Optional** | [Action button options](#action-button-options) | |
+| Name | Type | Requirement | Description | Default |
+| -------------- | ------- | ------------ | ------------------------------------------------------------------------------------------------ | ---------------------- |
+| type | string | **Required** | `custom:slider-button-card` | |
+| entity | string | **Required** | HA entity ID from domain `light, switch, fan, cover, input_boolean, media_player, climate, lock` | |
+| attribute | string | **Optional** | Entity attribute to display | |
+| name | string | **Optional** | Name | `entity.friendly_name` |
+| show_name | boolean | **Optional** | Show name | `true` |
+| show_state | boolean | **Optional** | Show state | `true` |
+| show_attribute | boolean | **Optional** | Show attribute | `false` |
+| compact | boolean | **Optional** | Compact mode, display name and state inline with icon. Useful for full width cards. | `false` |
+| icon | object | **Optional** | [Icon options](#icon-options) | |
+| slider | object | **Optional** | [Slider options](#slider-options) | |
+| action_button | object | **Optional** | [Action button options](#action-button-options) | |
### Icon Options
-| Name | Type | Requirement | Description | Default |
-| ----------------- | ------- | ------------ | ------------------------------------------- | ------------------- |
-| icon | string | **Optional** | Icon | `default entity icon` |
-| show | boolean | **Optional** | Show icon | `true` |
-| use_state_color | boolean | **Optional** | Use state color | `true` |
-| tap_action | object | **Optional** | [Action](#action-options) to take on tap | `action: more-info` |
+| Name | Type | Requirement | Description | Default |
+| --------------- | ------- | ------------ | ---------------------------------------- | --------------------- |
+| icon | string | **Optional** | Icon | `default entity icon` |
+| show | boolean | **Optional** | Show icon | `true` |
+| use_state_color | boolean | **Optional** | Use state color | `true` |
+| tap_action | object | **Optional** | [Action](#action-options) to take on tap | `action: more-info` |
### Slider Options
-| Name | Type | Requirement | Description | Default |
-| ----------------- | ------- | ------------ | ------------------------------------------- | ------------------- |
-| direction | string | **Optional** | Direction `left-right, top-bottom, bottom-top` | `left-right` |
-| background | string | **Optional** | Background `solid, gradient, triangle, striped, custom` | `gradient` |
-| use_state_color | boolean | **Optional** | Use state color | `true` |
-| use_percentage_bg_opacity | boolean | **Optional** | Apply opacity to background based on percentage | `true` |
-| show_track | boolean | **Optional** | Show track when state is on | `false` |
-| force_square | boolean | **Optional** | Force the button as a square | `false` |
-| toggle_on_click | boolean | **Optional** | Force the slider to act as a toggle, if `true` sliding is disabled | `false` |
-| attribute | string | **Optional** | Control an [attribute](#attributes) for `light` or `cover` entities | |
-| invert | boolean | **Optional** | Invert calculation of state and percentage, useful for `cover` entities | `false`
`true` for `cover` |
+| Name | Type | Requirement | Description | Default |
+| ------------------------- | ------- | ------------ | ----------------------------------------------------------------------- | -------------------------------------------------------------- |
+| direction | string | **Optional** | Direction `left-right, top-bottom, bottom-top` | `left-right` |
+| background | string | **Optional** | Background `solid, gradient, triangle, striped, custom` | `gradient` |
+| use_state_color | boolean | **Optional** | Use state color | `true` |
+| use_percentage_bg_opacity | boolean | **Optional** | Apply opacity to background based on percentage | `true` |
+| show_track | boolean | **Optional** | Show track when state is on | `false` |
+| force_square | boolean | **Optional** | Force the button as a square | `false` |
+| disable_sliding | boolean | **Optional** | Disable sliding, if `true` sliding is disabled | `false` |
+| attribute | string | **Optional** | Control an [attribute](#attributes) for `light` or `cover` entities | |
+| invert | boolean | **Optional** | Invert calculation of state and percentage, useful for `cover` entities | `false`
`true` for `cover` |
+| tap_action | object | **Optional** | [Action](#action-options) to take on tap | `action: more-info` or `action: toggle` depending on card type |
+
### Attributes
Light:
@@ -120,13 +141,13 @@ Cover:
- `tilt`
### Action button Options
-| Name | Type | Requirement | Description | Default |
-| ----------------- | ------- | ------------ | ------------------------------------------- | ------------------- |
-| mode | string | **Optional** | Mode `toggle, custom` | `toggle` |
-| show | boolean | **Optional** | Show the action button | `true` |
-| icon | string | **Optional** | Icon when mode is `custom` | `mdi:power` |
-| show_spinner | boolean | **Optional** | Show spinner when mode is `custom` | `true` |
-| tap_action | object | **Optional** | [Action](#action-options) to take on tap | `action: toggle` |
+| Name | Type | Requirement | Description | Default |
+| ------------ | ------- | ------------ | ---------------------------------------- | ---------------- |
+| mode | string | **Optional** | Mode `toggle, custom` | `toggle` |
+| show | boolean | **Optional** | Show the action button | `true` |
+| icon | string | **Optional** | Icon when mode is `custom` | `mdi:power` |
+| show_spinner | boolean | **Optional** | Show spinner when mode is `custom` | `true` |
+| tap_action | object | **Optional** | [Action](#action-options) to take on tap | `action: toggle` |
### Action Options
@@ -148,16 +169,16 @@ Custom styles can be set by using [Card mod](https://github.com/thomasloven/love
}
```
-| Variable | Description | Default |
-| ----------------------- | ------------------------------------------- | ------------------- |
-| `--icon-color` | Color of the icon when `icon.use_state_color === false` | `var(--paper-item-icon-color)` |
-| `--label-color-on` | Color of the label when state is on | `var(--primary-text-color, white)` |
-| `--label-color-off` | Color of the label when state is off | `var(--primary-text-color, white)` |
-| `--state-color-on` | Color of the state value when state is on | `var(--label-badge-text-color, white)` |
-| `--state-color-off` | Color of the state value when state is off | `var(--disabled-text-color)` |
-| `--action-icon-color-on` | Color of the action button icon when state is on | `var(--paper-item-icon-color, black)` |
-| `--action-icon-color-off` | Color of the action button icon when state is off | `var(--paper-item-icon-color, black)` |
-| `--action-spinner-color` | Color of the spinner action button | `var(--label-badge-text-color, white)` |
+| Variable | Description | Default |
+| ------------------------- | ------------------------------------------------------- | -------------------------------------- |
+| `--icon-color` | Color of the icon when `icon.use_state_color === false` | `var(--paper-item-icon-color)` |
+| `--label-color-on` | Color of the label when state is on | `var(--primary-text-color, white)` |
+| `--label-color-off` | Color of the label when state is off | `var(--primary-text-color, white)` |
+| `--state-color-on` | Color of the state value when state is on | `var(--label-badge-text-color, white)` |
+| `--state-color-off` | Color of the state value when state is off | `var(--disabled-text-color)` |
+| `--action-icon-color-on` | Color of the action button icon when state is on | `var(--paper-item-icon-color, black)` |
+| `--action-icon-color-off` | Color of the action button icon when state is off | `var(--paper-item-icon-color, black)` |
+| `--action-spinner-color` | Color of the spinner action button | `var(--label-badge-text-color, white)` |
## Examples
@@ -169,7 +190,7 @@ Custom styles can be set by using [Card mod](https://github.com/thomasloven/love
-
+ |
|
@@ -450,7 +514,7 @@ name: Fan
#### Switch
- Use `slider.toggle_on_click: true` so the slider acts as a toggle (sliding is disabled).
+ Use `slider.disable_sliding: true` so the slider is disabled, and `slider.tap_action.action: toggle` to toggle on tap.
|
@@ -458,7 +522,7 @@ name: Fan
-
+ |
|
@@ -468,7 +532,9 @@ entity: switch.socket
slider:
direction: left-right
background: custom
- toggle_on_click: true
+ disable_sliding: true
+ tap_action:
+ action: toggle
icon:
use_state_color: true
tap_action:
@@ -492,7 +558,7 @@ For most use cases: set `slider.direction: top-bottom` and `slider.background: s
|
-
+ |
|
@@ -519,7 +585,7 @@ name: Cover
#### Media player
Default behavior: slider is used for volume control, when there is an entity picture it will be used instead of the icon.
-In this example the action button is used to toggle play/pause.
+In this example the action button is used to toggle play/pause. Tapping on the body of the card will bring up the entity detail.
|
@@ -527,7 +593,7 @@ In this example the action button is used to toggle play/pause.
-
+ |
|
@@ -538,6 +604,8 @@ slider:
direction: left-right
background: triangle
show_track: true
+ tap_action:
+ action: more-info
icon:
tap_action:
action: more-info
@@ -565,7 +633,7 @@ Default behavior: slider is used to set target temperature, it doesn't alter sta
|
-
+ |
|
@@ -576,6 +644,8 @@ slider:
direction: left-right
background: triangle
show_track: true
+ tap_action:
+ action: more-info
icon:
tap_action:
action: more-info
@@ -591,7 +661,7 @@ name: Airco
|
#### Lock
-Default behavior: `slider.toggle_on_click: true`
+Default behavior: `slider.disable_sliding: true` and `slider.tap_action.action: toggle`
|
@@ -599,7 +669,7 @@ Default behavior: `slider.toggle_on_click: true`
-
+ |
|
@@ -609,7 +679,9 @@ entity: lock.virtual_lock
slider:
direction: left-right
background: solid
- toggle_on_click: true
+ disable_sliding: true
+ tap_action:
+ action: toggle
icon:
use_state_color: true
tap_action:
@@ -631,7 +703,7 @@ name: Lock
|
-
+ |
|
@@ -655,7 +727,9 @@ cards:
slider:
direction: left-right
background: custom
- toggle_on_click: true
+ disable_sliding: true
+ tap_action:
+ action: more-info
icon:
use_state_color: true
tap_action:
@@ -709,7 +783,7 @@ Mixed `group` entities are not supported, if you want to control multiple
- media players use [Media player group](https://www.home-assistant.io/integrations/media_player.group/)
## Known issues
-When you discover any bugs please open an [issue](https://github.com/mattieha/slider-button-card/issues).
+When you discover any bugs please open an [issue](https://github.com/lizsugar/slider-button-card/issues).
## Languages
@@ -730,17 +804,17 @@ This card supports translations. Please, help to add more translations and impro
- Inspired by [Slider entity row](https://github.com/thomasloven/lovelace-slider-entity-row)
---
-[](https://www.buymeacoffee.com/mattijsha)
+[](https://www.buymeacoffee.com/mattijsha) (original author: mattieha)
[hacs]: https://hacs.xyz
-[add-translation]: https://github.com/mattieha/slider-button-card/blob/main/CONTRIBUTE.md#adding-a-new-translation
-[visual-editor]: https://raw.githubusercontent.com/mattieha/slider-button-card/main/assets/card-editor.png
-[preview]: https://raw.githubusercontent.com/mattieha/slider-button-card/main/assets/preview.gif
-[preview-2]: https://raw.githubusercontent.com/mattieha/slider-button-card/main/assets/preview-2.gif
-[grid]: https://raw.githubusercontent.com/mattieha/slider-button-card/main/assets/grid-not-square.png
-[full-width]: https://raw.githubusercontent.com/mattieha/slider-button-card/main/assets/grid-full-width.png
-[latest-release]: https://github.com/mattieha/slider-button-card/releases/latest
-[releases-shield]: https://img.shields.io/github/release/mattieha/slider-button-card.svg?style=for-the-badge
-[releases]: https://github.com/mattieha/slider-button-card/releases
-[icon-minimal]: https://raw.githubusercontent.com/mattieha/slider-button-card/main/assets/grid-full-width.png
+[add-translation]: https://github.com/lizsugar/slider-button-card/blob/main/CONTRIBUTE.md#adding-a-new-translation
+[visual-editor]: https://raw.githubusercontent.com/lizsugar/slider-button-card/main/assets/card-editor.png
+[preview]: https://raw.githubusercontent.com/lizsugar/slider-button-card/main/assets/preview.gif
+[preview-2]: https://raw.githubusercontent.com/lizsugar/slider-button-card/main/assets/preview-2.gif
+[grid]: https://raw.githubusercontent.com/lizsugar/slider-button-card/main/assets/grid-not-square.png
+[full-width]: https://raw.githubusercontent.com/lizsugar/slider-button-card/main/assets/grid-full-width.png
+[latest-release]: https://github.com/lizsugar/slider-button-card/releases/latest
+[releases-shield]: https://img.shields.io/github/release/lizsugar/slider-button-card.svg?style=for-the-badge
+[releases]: https://github.com/lizsugar/slider-button-card/releases
+[icon-minimal]: https://raw.githubusercontent.com/lizsugar/slider-button-card/main/assets/grid-full-width.png
diff --git a/assets/examples/general-attribute.png b/assets/examples/general-attribute.png
new file mode 100644
index 0000000..907ae48
Binary files /dev/null and b/assets/examples/general-attribute.png differ
diff --git a/assets/examples/slider-tap-action.png b/assets/examples/slider-tap-action.png
new file mode 100644
index 0000000..cf07aa6
Binary files /dev/null and b/assets/examples/slider-tap-action.png differ
diff --git a/dist/slider-button-card.js b/dist/slider-button-card.js
index 5ebcf3f..2b0411c 100644
--- a/dist/slider-button-card.js
+++ b/dist/slider-button-card.js
@@ -1,18 +1,762 @@
-/*! *****************************************************************************
-Copyright (c) Microsoft Corporation.
-
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.
-***************************************************************************** */
-function t(t,e,i,s){var r,o=arguments.length,n=o<3?e:null===s?s=Object.getOwnPropertyDescriptor(e,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(t,e,i,s);else for(var a=t.length-1;a>=0;a--)(r=t[a])&&(n=(o<3?r(n):o>3?r(e,i,n):r(e,i))||n);return o>3&&n&&Object.defineProperty(e,i,n),n}var e=/d{1,4}|M{1,4}|YY(?:YY)?|S{1,3}|Do|ZZ|Z|([HhMsDm])\1?|[aA]|"[^"]*"|'[^']*'/g,i="[^\\s]+",s=/\[([^]*?)\]/gm;function r(t,e){for(var i=[],s=0,r=t.length;s-1?s:null}};function n(t){for(var e=[],i=1;i3?0:(t-t%10!=10?1:0)*t%10]}},d=n({},h),u=function(t,e){for(void 0===e&&(e=2),t=String(t);t.length0?"-":"+")+u(100*Math.floor(Math.abs(e)/60)+Math.abs(e)%60,4)},Z:function(t){var e=t.getTimezoneOffset();return(e>0?"-":"+")+u(Math.floor(Math.abs(e)/60),2)+":"+u(Math.abs(e)%60,2)}},g=function(t){return+t-1},f=[null,"[1-9]\\d?"],b=[null,i],m=["isPm",i,function(t,e){var i=t.toLowerCase();return i===e.amPm[0]?0:i===e.amPm[1]?1:null}],_=["timezoneOffset","[^\\s]*?[\\+\\-]\\d\\d:?\\d\\d|[^\\s]*?Z?",function(t){var e=(t+"").match(/([+-]|\d\d)/gi);if(e){var i=60*+e[1]+parseInt(e[2],10);return"+"===e[0]?i:-i}return 0}],v=(o("monthNamesShort"),o("monthNames"),{default:"ddd MMM DD YYYY HH:mm:ss",shortDate:"M/D/YY",mediumDate:"MMM D, YYYY",longDate:"MMMM D, YYYY",fullDate:"dddd, MMMM D, YYYY",isoDate:"YYYY-MM-DD",isoDateTime:"YYYY-MM-DDTHH:mm:ssZ",shortTime:"HH:mm",mediumTime:"HH:mm:ss",longTime:"HH:mm:ss.SSS"});var y=function(t,i,r){if(void 0===i&&(i=v.default),void 0===r&&(r={}),"number"==typeof t&&(t=new Date(t)),"[object Date]"!==Object.prototype.toString.call(t)||isNaN(t.getTime()))throw new Error("Invalid Date pass to format");var o=[];i=(i=v[i]||i).replace(s,(function(t,e){return o.push(e),"@@@"}));var a=n(n({},d),r);return(i=i.replace(e,(function(e){return p[e](t,a)}))).replace(/@@@/g,(function(){return o.shift()}))};(function(){try{(new Date).toLocaleDateString("i")}catch(t){return"RangeError"===t.name}})(),function(){try{(new Date).toLocaleString("i")}catch(t){return"RangeError"===t.name}}(),function(){try{(new Date).toLocaleTimeString("i")}catch(t){return"RangeError"===t.name}}();function w(t){return t.substr(0,t.indexOf("."))}function S(t){return w(t.entity_id)}var k="hass:bookmark",x=["closed","locked","off"],O=function(t,e,i,s){s=s||{},i=null==i?{}:i;var r=new Event(e,{bubbles:void 0===s.bubbles||s.bubbles,cancelable:Boolean(s.cancelable),composed:void 0===s.composed||s.composed});return r.detail=i,t.dispatchEvent(r),r},T={alert:"hass:alert",automation:"hass:playlist-play",calendar:"hass:calendar",camera:"hass:video",climate:"hass:thermostat",configurator:"hass:settings",conversation:"hass:text-to-speech",device_tracker:"hass:account",fan:"hass:fan",group:"hass:google-circles-communities",history_graph:"hass:chart-line",homeassistant:"hass:home-assistant",homekit:"hass:home-automation",image_processing:"hass:image-filter-frames",input_boolean:"hass:drawing",input_datetime:"hass:calendar-clock",input_number:"hass:ray-vertex",input_select:"hass:format-list-bulleted",input_text:"hass:textbox",light:"hass:lightbulb",mailbox:"hass:mailbox",notify:"hass:comment-alert",person:"hass:account",plant:"hass:flower",proximity:"hass:apple-safari",remote:"hass:remote",scene:"hass:google-pages",script:"hass:file-document",sensor:"hass:eye",simple_alarm:"hass:bell",sun:"hass:white-balance-sunny",switch:"hass:flash",timer:"hass:timer",updater:"hass:cloud-upload",vacuum:"hass:robot-vacuum",water_heater:"hass:thermometer",weblink:"hass:open-in-new"};function C(t,e){if(t in T)return T[t];switch(t){case"alarm_control_panel":switch(e){case"armed_home":return"hass:bell-plus";case"armed_night":return"hass:bell-sleep";case"disarmed":return"hass:bell-outline";case"triggered":return"hass:bell-ring";default:return"hass:bell"}case"binary_sensor":return e&&"off"===e?"hass:radiobox-blank":"hass:checkbox-marked-circle";case"cover":return"closed"===e?"hass:window-closed":"hass:window-open";case"lock":return e&&"unlocked"===e?"hass:lock-open":"hass:lock";case"media_player":return e&&"off"!==e&&"idle"!==e?"hass:cast-connected":"hass:cast";case"zwave":switch(e){case"dead":return"hass:emoticon-dead";case"sleeping":return"hass:sleep";case"initializing":return"hass:timer-sand";default:return"hass:z-wave"}default:return console.warn("Unable to find icon for domain "+t+" ("+e+")"),k}}var M=function(t){O(window,"haptic",t)},P=function(t,e){return function(t,e,i){void 0===i&&(i=!0);var s,r=w(e),o="group"===r?"homeassistant":r;switch(r){case"lock":s=i?"unlock":"lock";break;case"cover":s=i?"open_cover":"close_cover";break;default:s=i?"turn_on":"turn_off"}return t.callService(o,s,{entity_id:e})}(t,e,x.includes(t.states[e].state))},E=function(t,e,i,s){if(s||(s={action:"more-info"}),!s.confirmation||s.confirmation.exemptions&&s.confirmation.exemptions.some((function(t){return t.user===e.user.id}))||(M("warning"),confirm(s.confirmation.text||"Are you sure you want to "+s.action+"?")))switch(s.action){case"more-info":(i.entity||i.camera_image)&&O(t,"hass-more-info",{entityId:i.entity?i.entity:i.camera_image});break;case"navigate":s.navigation_path&&function(t,e,i){void 0===i&&(i=!1),i?history.replaceState(null,"",e):history.pushState(null,"",e),O(window,"location-changed",{replace:i})}(0,s.navigation_path);break;case"url":s.url_path&&window.open(s.url_path);break;case"toggle":i.entity&&(P(e,i.entity),M("success"));break;case"call-service":if(!s.service)return void M("failure");var r=s.service.split(".",2);e.callService(r[0],r[1],s.service_data),M("success");break;case"fire-dom-event":O(t,"ll-custom",s)}},A=function(t,e,i,s){var r;"double_tap"===s&&i.double_tap_action?r=i.double_tap_action:"hold"===s&&i.hold_action?r=i.hold_action:"tap"===s&&i.tap_action&&(r=i.tap_action),E(t,e,i,r)};var $={humidity:"hass:water-percent",illuminance:"hass:brightness-5",temperature:"hass:thermometer",pressure:"hass:gauge",power:"hass:flash",signal_strength:"hass:wifi"},N={binary_sensor:function(t){var e=t.state&&"off"===t.state;switch(t.attributes.device_class){case"battery":return e?"hass:battery":"hass:battery-outline";case"cold":return e?"hass:thermometer":"hass:snowflake";case"connectivity":return e?"hass:server-network-off":"hass:server-network";case"door":return e?"hass:door-closed":"hass:door-open";case"garage_door":return e?"hass:garage":"hass:garage-open";case"gas":case"power":case"problem":case"safety":case"smoke":return e?"hass:shield-check":"hass:alert";case"heat":return e?"hass:thermometer":"hass:fire";case"light":return e?"hass:brightness-5":"hass:brightness-7";case"lock":return e?"hass:lock":"hass:lock-open";case"moisture":return e?"hass:water-off":"hass:water";case"motion":return e?"hass:walk":"hass:run";case"occupancy":return e?"hass:home-outline":"hass:home";case"opening":return e?"hass:square":"hass:square-outline";case"plug":return e?"hass:power-plug-off":"hass:power-plug";case"presence":return e?"hass:home-outline":"hass:home";case"sound":return e?"hass:music-note-off":"hass:music-note";case"vibration":return e?"hass:crop-portrait":"hass:vibrate";case"window":return e?"hass:window-closed":"hass:window-open";default:return e?"hass:radiobox-blank":"hass:checkbox-marked-circle"}},cover:function(t){var e="closed"!==t.state;switch(t.attributes.device_class){case"garage":return e?"hass:garage-open":"hass:garage";case"door":return e?"hass:door-open":"hass:door-closed";case"shutter":return e?"hass:window-shutter-open":"hass:window-shutter";case"blind":return e?"hass:blinds-open":"hass:blinds";case"window":return e?"hass:window-open":"hass:window-closed";default:return C("cover",t.state)}},sensor:function(t){var e=t.attributes.device_class;if(e&&e in $)return $[e];if("battery"===e){var i=Number(t.state);if(isNaN(i))return"hass:battery-unknown";var s=10*Math.round(i/10);return s>=100?"hass:battery":s<=0?"hass:battery-alert":"hass:battery-"+s}var r=t.attributes.unit_of_measurement;return"°C"===r||"°F"===r?"hass:thermometer":C("sensor")},input_datetime:function(t){return t.attributes.has_date?t.attributes.has_time?C("input_datetime"):"hass:calendar":"hass:clock"}},j=function(t){if(!t)return k;if(t.attributes.icon)return t.attributes.icon;var e=w(t.entity_id);return e in N?N[e](t):C(e,t.state)},R=Function.prototype.toString,I=Object.create,V=Object.defineProperty,H=Object.getOwnPropertyDescriptor,L=Object.getOwnPropertyNames,U=Object.getOwnPropertySymbols,z=Object.getPrototypeOf,D=Object.prototype,F=D.hasOwnProperty,B=D.propertyIsEnumerable,q="function"==typeof U,G="function"==typeof WeakMap,Y=function(t,e){if(!t.constructor)return I(null);var i=t.constructor,s=t.__proto__||z(t);if(i===e.Object)return s===e.Object.prototype?{}:I(s);if(~R.call(i).indexOf("[native code]"))try{return new i}catch(t){}return I(s)},W=function(t,e,i,s){var r=Y(t,e);for(var o in s.set(t,r),t)F.call(t,o)&&(r[o]=i(t[o],s));if(q){var n=U(t),a=n.length;if(a)for(var l=0,c=void 0;l= 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;
+}
+
+var token = /d{1,4}|M{1,4}|YY(?:YY)?|S{1,3}|Do|ZZ|Z|([HhMsDm])\1?|[aA]|"[^"]*"|'[^']*'/g;
+var twoDigitsOptional = "[1-9]\\d?";
+var twoDigits = "\\d\\d";
+var threeDigits = "\\d{3}";
+var fourDigits = "\\d{4}";
+var word = "[^\\s]+";
+var literal = /\[([^]*?)\]/gm;
+function shorten(arr, sLen) {
+ var newArr = [];
+ for (var i = 0, len = arr.length; i < len; i++) {
+ newArr.push(arr[i].substr(0, sLen));
+ }
+ return newArr;
+}
+var monthUpdate = function (arrName) { return function (v, i18n) {
+ var lowerCaseArr = i18n[arrName].map(function (v) { return v.toLowerCase(); });
+ var index = lowerCaseArr.indexOf(v.toLowerCase());
+ if (index > -1) {
+ return index;
+ }
+ return null;
+}; };
+function assign(origObj) {
+ var args = [];
+ for (var _i = 1; _i < arguments.length; _i++) {
+ args[_i - 1] = arguments[_i];
+ }
+ for (var _a = 0, args_1 = args; _a < args_1.length; _a++) {
+ var obj = args_1[_a];
+ for (var key in obj) {
+ // @ts-ignore ex
+ origObj[key] = obj[key];
+ }
+ }
+ return origObj;
+}
+var dayNames = [
+ "Sunday",
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday"
+];
+var monthNames = [
+ "January",
+ "February",
+ "March",
+ "April",
+ "May",
+ "June",
+ "July",
+ "August",
+ "September",
+ "October",
+ "November",
+ "December"
+];
+var monthNamesShort = shorten(monthNames, 3);
+var dayNamesShort = shorten(dayNames, 3);
+var defaultI18n = {
+ dayNamesShort: dayNamesShort,
+ dayNames: dayNames,
+ monthNamesShort: monthNamesShort,
+ monthNames: monthNames,
+ amPm: ["am", "pm"],
+ DoFn: function (dayOfMonth) {
+ return (dayOfMonth +
+ ["th", "st", "nd", "rd"][dayOfMonth % 10 > 3
+ ? 0
+ : ((dayOfMonth - (dayOfMonth % 10) !== 10 ? 1 : 0) * dayOfMonth) % 10]);
+ }
+};
+var globalI18n = assign({}, defaultI18n);
+var setGlobalDateI18n = function (i18n) {
+ return (globalI18n = assign(globalI18n, i18n));
+};
+var regexEscape = function (str) {
+ return str.replace(/[|\\{()[^$+*?.-]/g, "\\$&");
+};
+var pad = function (val, len) {
+ if (len === void 0) { len = 2; }
+ val = String(val);
+ while (val.length < len) {
+ val = "0" + val;
+ }
+ return val;
+};
+var formatFlags = {
+ D: function (dateObj) { return String(dateObj.getDate()); },
+ DD: function (dateObj) { return pad(dateObj.getDate()); },
+ Do: function (dateObj, i18n) {
+ return i18n.DoFn(dateObj.getDate());
+ },
+ d: function (dateObj) { return String(dateObj.getDay()); },
+ dd: function (dateObj) { return pad(dateObj.getDay()); },
+ ddd: function (dateObj, i18n) {
+ return i18n.dayNamesShort[dateObj.getDay()];
+ },
+ dddd: function (dateObj, i18n) {
+ return i18n.dayNames[dateObj.getDay()];
+ },
+ M: function (dateObj) { return String(dateObj.getMonth() + 1); },
+ MM: function (dateObj) { return pad(dateObj.getMonth() + 1); },
+ MMM: function (dateObj, i18n) {
+ return i18n.monthNamesShort[dateObj.getMonth()];
+ },
+ MMMM: function (dateObj, i18n) {
+ return i18n.monthNames[dateObj.getMonth()];
+ },
+ YY: function (dateObj) {
+ return pad(String(dateObj.getFullYear()), 4).substr(2);
+ },
+ YYYY: function (dateObj) { return pad(dateObj.getFullYear(), 4); },
+ h: function (dateObj) { return String(dateObj.getHours() % 12 || 12); },
+ hh: function (dateObj) { return pad(dateObj.getHours() % 12 || 12); },
+ H: function (dateObj) { return String(dateObj.getHours()); },
+ HH: function (dateObj) { return pad(dateObj.getHours()); },
+ m: function (dateObj) { return String(dateObj.getMinutes()); },
+ mm: function (dateObj) { return pad(dateObj.getMinutes()); },
+ s: function (dateObj) { return String(dateObj.getSeconds()); },
+ ss: function (dateObj) { return pad(dateObj.getSeconds()); },
+ S: function (dateObj) {
+ return String(Math.round(dateObj.getMilliseconds() / 100));
+ },
+ SS: function (dateObj) {
+ return pad(Math.round(dateObj.getMilliseconds() / 10), 2);
+ },
+ SSS: function (dateObj) { return pad(dateObj.getMilliseconds(), 3); },
+ a: function (dateObj, i18n) {
+ return dateObj.getHours() < 12 ? i18n.amPm[0] : i18n.amPm[1];
+ },
+ A: function (dateObj, i18n) {
+ return dateObj.getHours() < 12
+ ? i18n.amPm[0].toUpperCase()
+ : i18n.amPm[1].toUpperCase();
+ },
+ ZZ: function (dateObj) {
+ var offset = dateObj.getTimezoneOffset();
+ return ((offset > 0 ? "-" : "+") +
+ pad(Math.floor(Math.abs(offset) / 60) * 100 + (Math.abs(offset) % 60), 4));
+ },
+ Z: function (dateObj) {
+ var offset = dateObj.getTimezoneOffset();
+ return ((offset > 0 ? "-" : "+") +
+ pad(Math.floor(Math.abs(offset) / 60), 2) +
+ ":" +
+ pad(Math.abs(offset) % 60, 2));
+ }
+};
+var monthParse = function (v) { return +v - 1; };
+var emptyDigits = [null, twoDigitsOptional];
+var emptyWord = [null, word];
+var amPm = [
+ "isPm",
+ word,
+ function (v, i18n) {
+ var val = v.toLowerCase();
+ if (val === i18n.amPm[0]) {
+ return 0;
+ }
+ else if (val === i18n.amPm[1]) {
+ return 1;
+ }
+ return null;
+ }
+];
+var timezoneOffset = [
+ "timezoneOffset",
+ "[^\\s]*?[\\+\\-]\\d\\d:?\\d\\d|[^\\s]*?Z?",
+ function (v) {
+ var parts = (v + "").match(/([+-]|\d\d)/gi);
+ if (parts) {
+ var minutes = +parts[1] * 60 + parseInt(parts[2], 10);
+ return parts[0] === "+" ? minutes : -minutes;
+ }
+ return 0;
+ }
+];
+var parseFlags = {
+ D: ["day", twoDigitsOptional],
+ DD: ["day", twoDigits],
+ Do: ["day", twoDigitsOptional + word, function (v) { return parseInt(v, 10); }],
+ M: ["month", twoDigitsOptional, monthParse],
+ MM: ["month", twoDigits, monthParse],
+ YY: [
+ "year",
+ twoDigits,
+ function (v) {
+ var now = new Date();
+ var cent = +("" + now.getFullYear()).substr(0, 2);
+ return +("" + (+v > 68 ? cent - 1 : cent) + v);
+ }
+ ],
+ h: ["hour", twoDigitsOptional, undefined, "isPm"],
+ hh: ["hour", twoDigits, undefined, "isPm"],
+ H: ["hour", twoDigitsOptional],
+ HH: ["hour", twoDigits],
+ m: ["minute", twoDigitsOptional],
+ mm: ["minute", twoDigits],
+ s: ["second", twoDigitsOptional],
+ ss: ["second", twoDigits],
+ YYYY: ["year", fourDigits],
+ S: ["millisecond", "\\d", function (v) { return +v * 100; }],
+ SS: ["millisecond", twoDigits, function (v) { return +v * 10; }],
+ SSS: ["millisecond", threeDigits],
+ d: emptyDigits,
+ dd: emptyDigits,
+ ddd: emptyWord,
+ dddd: emptyWord,
+ MMM: ["month", word, monthUpdate("monthNamesShort")],
+ MMMM: ["month", word, monthUpdate("monthNames")],
+ a: amPm,
+ A: amPm,
+ ZZ: timezoneOffset,
+ Z: timezoneOffset
+};
+// Some common format strings
+var globalMasks = {
+ default: "ddd MMM DD YYYY HH:mm:ss",
+ shortDate: "M/D/YY",
+ mediumDate: "MMM D, YYYY",
+ longDate: "MMMM D, YYYY",
+ fullDate: "dddd, MMMM D, YYYY",
+ isoDate: "YYYY-MM-DD",
+ isoDateTime: "YYYY-MM-DDTHH:mm:ssZ",
+ shortTime: "HH:mm",
+ mediumTime: "HH:mm:ss",
+ longTime: "HH:mm:ss.SSS"
+};
+var setGlobalDateMasks = function (masks) { return assign(globalMasks, masks); };
+/***
+ * Format a date
+ * @method format
+ * @param {Date|number} dateObj
+ * @param {string} mask Format of the date, i.e. 'mm-dd-yy' or 'shortDate'
+ * @returns {string} Formatted date string
+ */
+var format = function (dateObj, mask, i18n) {
+ if (mask === void 0) { mask = globalMasks["default"]; }
+ if (i18n === void 0) { i18n = {}; }
+ if (typeof dateObj === "number") {
+ dateObj = new Date(dateObj);
+ }
+ if (Object.prototype.toString.call(dateObj) !== "[object Date]" ||
+ isNaN(dateObj.getTime())) {
+ throw new Error("Invalid Date pass to format");
+ }
+ mask = globalMasks[mask] || mask;
+ var literals = [];
+ // Make literals inactive by replacing them with @@@
+ mask = mask.replace(literal, function ($0, $1) {
+ literals.push($1);
+ return "@@@";
+ });
+ var combinedI18nSettings = assign(assign({}, globalI18n), i18n);
+ // Apply formatting rules
+ mask = mask.replace(token, function ($0) {
+ return formatFlags[$0](dateObj, combinedI18nSettings);
+ });
+ // Inline literal values back into the formatted value
+ return mask.replace(/@@@/g, function () { return literals.shift(); });
+};
+/**
+ * Parse a date string into a Javascript Date object /
+ * @method parse
+ * @param {string} dateStr Date string
+ * @param {string} format Date parse format
+ * @param {i18n} I18nSettingsOptional Full or subset of I18N settings
+ * @returns {Date|null} Returns Date object. Returns null what date string is invalid or doesn't match format
+ */
+function parse(dateStr, format, i18n) {
+ if (i18n === void 0) { i18n = {}; }
+ if (typeof format !== "string") {
+ throw new Error("Invalid format in fecha parse");
+ }
+ // Check to see if the format is actually a mask
+ format = globalMasks[format] || format;
+ // Avoid regular expression denial of service, fail early for really long strings
+ // https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS
+ if (dateStr.length > 1000) {
+ return null;
+ }
+ // Default to the beginning of the year.
+ var today = new Date();
+ var dateInfo = {
+ year: today.getFullYear(),
+ month: 0,
+ day: 1,
+ hour: 0,
+ minute: 0,
+ second: 0,
+ millisecond: 0,
+ isPm: null,
+ timezoneOffset: null
+ };
+ var parseInfo = [];
+ var literals = [];
+ // Replace all the literals with @@@. Hopefully a string that won't exist in the format
+ var newFormat = format.replace(literal, function ($0, $1) {
+ literals.push(regexEscape($1));
+ return "@@@";
+ });
+ var specifiedFields = {};
+ var requiredFields = {};
+ // Change every token that we find into the correct regex
+ newFormat = regexEscape(newFormat).replace(token, function ($0) {
+ var info = parseFlags[$0];
+ var field = info[0], regex = info[1], requiredField = info[3];
+ // Check if the person has specified the same field twice. This will lead to confusing results.
+ if (specifiedFields[field]) {
+ throw new Error("Invalid format. " + field + " specified twice in format");
+ }
+ specifiedFields[field] = true;
+ // Check if there are any required fields. For instance, 12 hour time requires AM/PM specified
+ if (requiredField) {
+ requiredFields[requiredField] = true;
+ }
+ parseInfo.push(info);
+ return "(" + regex + ")";
+ });
+ // Check all the required fields are present
+ Object.keys(requiredFields).forEach(function (field) {
+ if (!specifiedFields[field]) {
+ throw new Error("Invalid format. " + field + " is required in specified format");
+ }
+ });
+ // Add back all the literals after
+ newFormat = newFormat.replace(/@@@/g, function () { return literals.shift(); });
+ // Check if the date string matches the format. If it doesn't return null
+ var matches = dateStr.match(new RegExp(newFormat, "i"));
+ if (!matches) {
+ return null;
+ }
+ var combinedI18nSettings = assign(assign({}, globalI18n), i18n);
+ // For each match, call the parser function for that date part
+ for (var i = 1; i < matches.length; i++) {
+ var _a = parseInfo[i - 1], field = _a[0], parser = _a[2];
+ var value = parser
+ ? parser(matches[i], combinedI18nSettings)
+ : +matches[i];
+ // If the parser can't make sense of the value, return null
+ if (value == null) {
+ return null;
+ }
+ dateInfo[field] = value;
+ }
+ if (dateInfo.isPm === 1 && dateInfo.hour != null && +dateInfo.hour !== 12) {
+ dateInfo.hour = +dateInfo.hour + 12;
+ }
+ else if (dateInfo.isPm === 0 && +dateInfo.hour === 12) {
+ dateInfo.hour = 0;
+ }
+ var dateWithoutTZ = new Date(dateInfo.year, dateInfo.month, dateInfo.day, dateInfo.hour, dateInfo.minute, dateInfo.second, dateInfo.millisecond);
+ var validateFields = [
+ ["month", "getMonth"],
+ ["day", "getDate"],
+ ["hour", "getHours"],
+ ["minute", "getMinutes"],
+ ["second", "getSeconds"]
+ ];
+ for (var i = 0, len = validateFields.length; i < len; i++) {
+ // Check to make sure the date field is within the allowed range. Javascript dates allows values
+ // outside the allowed range. If the values don't match the value was invalid
+ if (specifiedFields[validateFields[i][0]] &&
+ dateInfo[validateFields[i][0]] !== dateWithoutTZ[validateFields[i][1]]()) {
+ return null;
+ }
+ }
+ if (dateInfo.timezoneOffset == null) {
+ return dateWithoutTZ;
+ }
+ return new Date(Date.UTC(dateInfo.year, dateInfo.month, dateInfo.day, dateInfo.hour, dateInfo.minute - dateInfo.timezoneOffset, dateInfo.second, dateInfo.millisecond));
+}
+var fecha = {
+ format: format,
+ parse: parse,
+ defaultI18n: defaultI18n,
+ setGlobalDateI18n: setGlobalDateI18n,
+ setGlobalDateMasks: setGlobalDateMasks
+};
+
+(function(){try{(new Date).toLocaleDateString("i");}catch(e){return "RangeError"===e.name}return !1})()?function(e,t){return e.toLocaleDateString(t,{year:"numeric",month:"long",day:"numeric"})}:function(t){return fecha.format(t,"mediumDate")};(function(){try{(new Date).toLocaleString("i");}catch(e){return "RangeError"===e.name}return !1})()?function(e,t){return e.toLocaleString(t,{year:"numeric",month:"long",day:"numeric",hour:"numeric",minute:"2-digit"})}:function(t){return fecha.format(t,"haDateTime")};(function(){try{(new Date).toLocaleTimeString("i");}catch(e){return "RangeError"===e.name}return !1})()?function(e,t){return e.toLocaleTimeString(t,{hour:"numeric",minute:"2-digit"})}:function(t){return fecha.format(t,"shortTime")};var h=function(e,t,a,r){void 0===r&&(r=!1),e._themes||(e._themes={});var n=t.default_theme;("default"===a||a&&t.themes[a])&&(n=a);var s=Object.assign({},e._themes);if("default"!==n){var i=t.themes[n];Object.keys(i).forEach(function(t){var a="--"+t;e._themes[a]="",s[a]=i[t];});}if(e.updateStyles?e.updateStyles(s):window.ShadyCSS&&window.ShadyCSS.styleSubtree(e,s),r){var o=document.querySelector("meta[name=theme-color]");if(o){o.hasAttribute("default-content")||o.setAttribute("default-content",o.getAttribute("content"));var c=s["--primary-color"]||o.getAttribute("default-content");o.setAttribute("content",c);}}};function f(e){return e.substr(0,e.indexOf("."))}function v(e){return f(e.entity_id)}var _="hass:bookmark",D=["closed","locked","off"],q=function(e,t,a,r){r=r||{},a=null==a?{}:a;var n=new Event(t,{bubbles:void 0===r.bubbles||r.bubbles,cancelable:Boolean(r.cancelable),composed:void 0===r.composed||r.composed});return n.detail=a,e.dispatchEvent(n),n},L={alert:"hass:alert",automation:"hass:playlist-play",calendar:"hass:calendar",camera:"hass:video",climate:"hass:thermostat",configurator:"hass:settings",conversation:"hass:text-to-speech",device_tracker:"hass:account",fan:"hass:fan",group:"hass:google-circles-communities",history_graph:"hass:chart-line",homeassistant:"hass:home-assistant",homekit:"hass:home-automation",image_processing:"hass:image-filter-frames",input_boolean:"hass:drawing",input_datetime:"hass:calendar-clock",input_number:"hass:ray-vertex",input_select:"hass:format-list-bulleted",input_text:"hass:textbox",light:"hass:lightbulb",mailbox:"hass:mailbox",notify:"hass:comment-alert",person:"hass:account",plant:"hass:flower",proximity:"hass:apple-safari",remote:"hass:remote",scene:"hass:google-pages",script:"hass:file-document",sensor:"hass:eye",simple_alarm:"hass:bell",sun:"hass:white-balance-sunny",switch:"hass:flash",timer:"hass:timer",updater:"hass:cloud-upload",vacuum:"hass:robot-vacuum",water_heater:"hass:thermometer",weblink:"hass:open-in-new"};function O(e,t){if(e in L)return L[e];switch(e){case"alarm_control_panel":switch(t){case"armed_home":return "hass:bell-plus";case"armed_night":return "hass:bell-sleep";case"disarmed":return "hass:bell-outline";case"triggered":return "hass:bell-ring";default:return "hass:bell"}case"binary_sensor":return t&&"off"===t?"hass:radiobox-blank":"hass:checkbox-marked-circle";case"cover":return "closed"===t?"hass:window-closed":"hass:window-open";case"lock":return t&&"unlocked"===t?"hass:lock-open":"hass:lock";case"media_player":return t&&"off"!==t&&"idle"!==t?"hass:cast-connected":"hass:cast";case"zwave":switch(t){case"dead":return "hass:emoticon-dead";case"sleeping":return "hass:sleep";case"initializing":return "hass:timer-sand";default:return "hass:z-wave"}default:return console.warn("Unable to find icon for domain "+e+" ("+t+")"),_}}var B=function(e){q(window,"haptic",e);},U=function(e,t,a){void 0===a&&(a=!1),a?history.replaceState(null,"",t):history.pushState(null,"",t),q(window,"location-changed",{replace:a});},V=function(e,t,a){void 0===a&&(a=!0);var r,n=f(t),s="group"===n?"homeassistant":n;switch(n){case"lock":r=a?"unlock":"lock";break;case"cover":r=a?"open_cover":"close_cover";break;default:r=a?"turn_on":"turn_off";}return e.callService(s,r,{entity_id:t})},W=function(e,t){var a=D.includes(e.states[t].state);return V(e,t,a)},Y=function(e,t,a,r){if(r||(r={action:"more-info"}),!r.confirmation||r.confirmation.exemptions&&r.confirmation.exemptions.some(function(e){return e.user===t.user.id})||(B("warning"),confirm(r.confirmation.text||"Are you sure you want to "+r.action+"?")))switch(r.action){case"more-info":(a.entity||a.camera_image)&&q(e,"hass-more-info",{entityId:a.entity?a.entity:a.camera_image});break;case"navigate":r.navigation_path&&U(0,r.navigation_path);break;case"url":r.url_path&&window.open(r.url_path);break;case"toggle":a.entity&&(W(t,a.entity),B("success"));break;case"call-service":if(!r.service)return void B("failure");var n=r.service.split(".",2);t.callService(n[0],n[1],r.service_data),B("success");break;case"fire-dom-event":q(e,"ll-custom",r);}},G=function(e,t,a,r){var n;"double_tap"===r&&a.double_tap_action?n=a.double_tap_action:"hold"===r&&a.hold_action?n=a.hold_action:"tap"===r&&a.tap_action&&(n=a.tap_action),Y(e,t,a,n);};function K(e,t,a){if(t.has("config")||a)return !0;if(e.config.entity){var r=t.get("hass");return !r||r.states[e.config.entity]!==e.hass.states[e.config.entity]}return !1}var Z={humidity:"hass:water-percent",illuminance:"hass:brightness-5",temperature:"hass:thermometer",pressure:"hass:gauge",power:"hass:flash",signal_strength:"hass:wifi"},$={binary_sensor:function(e){var t=e.state&&"off"===e.state;switch(e.attributes.device_class){case"battery":return t?"hass:battery":"hass:battery-outline";case"cold":return t?"hass:thermometer":"hass:snowflake";case"connectivity":return t?"hass:server-network-off":"hass:server-network";case"door":return t?"hass:door-closed":"hass:door-open";case"garage_door":return t?"hass:garage":"hass:garage-open";case"gas":case"power":case"problem":case"safety":case"smoke":return t?"hass:shield-check":"hass:alert";case"heat":return t?"hass:thermometer":"hass:fire";case"light":return t?"hass:brightness-5":"hass:brightness-7";case"lock":return t?"hass:lock":"hass:lock-open";case"moisture":return t?"hass:water-off":"hass:water";case"motion":return t?"hass:walk":"hass:run";case"occupancy":return t?"hass:home-outline":"hass:home";case"opening":return t?"hass:square":"hass:square-outline";case"plug":return t?"hass:power-plug-off":"hass:power-plug";case"presence":return t?"hass:home-outline":"hass:home";case"sound":return t?"hass:music-note-off":"hass:music-note";case"vibration":return t?"hass:crop-portrait":"hass:vibrate";case"window":return t?"hass:window-closed":"hass:window-open";default:return t?"hass:radiobox-blank":"hass:checkbox-marked-circle"}},cover:function(e){var t="closed"!==e.state;switch(e.attributes.device_class){case"garage":return t?"hass:garage-open":"hass:garage";case"door":return t?"hass:door-open":"hass:door-closed";case"shutter":return t?"hass:window-shutter-open":"hass:window-shutter";case"blind":return t?"hass:blinds-open":"hass:blinds";case"window":return t?"hass:window-open":"hass:window-closed";default:return O("cover",e.state)}},sensor:function(e){var t=e.attributes.device_class;if(t&&t in Z)return Z[t];if("battery"===t){var a=Number(e.state);if(isNaN(a))return "hass:battery-unknown";var r=10*Math.round(a/10);return r>=100?"hass:battery":r<=0?"hass:battery-alert":"hass:battery-"+r}var n=e.attributes.unit_of_measurement;return "°C"===n||"°F"===n?"hass:thermometer":O("sensor")},input_datetime:function(e){return e.attributes.has_date?e.attributes.has_time?O("input_datetime"):"hass:calendar":"hass:clock"}},ee=function(e){if(!e)return _;if(e.attributes.icon)return e.attributes.icon;var t=f(e.entity_id);return t in $?$[t](e):O(t,e.state)};
+
+var toStringFunction = Function.prototype.toString;
+var create = Object.create, defineProperty = Object.defineProperty, getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor, getOwnPropertyNames = Object.getOwnPropertyNames, getOwnPropertySymbols = Object.getOwnPropertySymbols, getPrototypeOf = Object.getPrototypeOf;
+var _a$1 = Object.prototype, hasOwnProperty = _a$1.hasOwnProperty, propertyIsEnumerable = _a$1.propertyIsEnumerable;
+/**
+ * @enum
+ *
+ * @const {Object} SUPPORTS
+ *
+ * @property {boolean} SYMBOL_PROPERTIES are symbol properties supported
+ * @property {boolean} WEAKMAP is WeakMap supported
+ */
+var SUPPORTS = {
+ SYMBOL_PROPERTIES: typeof getOwnPropertySymbols === 'function',
+ WEAKMAP: typeof WeakMap === 'function',
+};
+/**
+ * @function createCache
+ *
+ * @description
+ * get a new cache object to prevent circular references
+ *
+ * @returns the new cache object
+ */
+var createCache = function () {
+ if (SUPPORTS.WEAKMAP) {
+ return new WeakMap();
+ }
+ // tiny implementation of WeakMap
+ var object = create({
+ has: function (key) { return !!~object._keys.indexOf(key); },
+ set: function (key, value) {
+ object._keys.push(key);
+ object._values.push(value);
+ },
+ get: function (key) { return object._values[object._keys.indexOf(key)]; },
+ });
+ object._keys = [];
+ object._values = [];
+ return object;
+};
+/**
+ * @function getCleanClone
+ *
+ * @description
+ * get an empty version of the object with the same prototype it has
+ *
+ * @param object the object to build a clean clone from
+ * @param realm the realm the object resides in
+ * @returns the empty cloned object
+ */
+var getCleanClone = function (object, realm) {
+ if (!object.constructor) {
+ return create(null);
+ }
+ var Constructor = object.constructor;
+ var prototype = object.__proto__ || getPrototypeOf(object);
+ if (Constructor === realm.Object) {
+ return prototype === realm.Object.prototype ? {} : create(prototype);
+ }
+ if (~toStringFunction.call(Constructor).indexOf('[native code]')) {
+ try {
+ return new Constructor();
+ }
+ catch (_a) { }
+ }
+ return create(prototype);
+};
+/**
+ * @function getObjectCloneLoose
+ *
+ * @description
+ * get a copy of the object based on loose rules, meaning all enumerable keys
+ * and symbols are copied, but property descriptors are not considered
+ *
+ * @param object the object to clone
+ * @param realm the realm the object resides in
+ * @param handleCopy the function that handles copying the object
+ * @returns the copied object
+ */
+var getObjectCloneLoose = function (object, realm, handleCopy, cache) {
+ var clone = getCleanClone(object, realm);
+ // set in the cache immediately to be able to reuse the object recursively
+ cache.set(object, clone);
+ for (var key in object) {
+ if (hasOwnProperty.call(object, key)) {
+ clone[key] = handleCopy(object[key], cache);
+ }
+ }
+ if (SUPPORTS.SYMBOL_PROPERTIES) {
+ var symbols = getOwnPropertySymbols(object);
+ var length_1 = symbols.length;
+ if (length_1) {
+ for (var index = 0, symbol = void 0; index < length_1; index++) {
+ symbol = symbols[index];
+ if (propertyIsEnumerable.call(object, symbol)) {
+ clone[symbol] = handleCopy(object[symbol], cache);
+ }
+ }
+ }
+ }
+ return clone;
+};
+/**
+ * @function getObjectCloneStrict
+ *
+ * @description
+ * get a copy of the object based on strict rules, meaning all keys and symbols
+ * are copied based on the original property descriptors
+ *
+ * @param object the object to clone
+ * @param realm the realm the object resides in
+ * @param handleCopy the function that handles copying the object
+ * @returns the copied object
+ */
+var getObjectCloneStrict = function (object, realm, handleCopy, cache) {
+ var clone = getCleanClone(object, realm);
+ // set in the cache immediately to be able to reuse the object recursively
+ cache.set(object, clone);
+ var properties = SUPPORTS.SYMBOL_PROPERTIES
+ ? getOwnPropertyNames(object).concat(getOwnPropertySymbols(object))
+ : getOwnPropertyNames(object);
+ var length = properties.length;
+ if (length) {
+ for (var index = 0, property = void 0, descriptor = void 0; index < length; index++) {
+ property = properties[index];
+ if (property !== 'callee' && property !== 'caller') {
+ descriptor = getOwnPropertyDescriptor(object, property);
+ if (descriptor) {
+ // Only clone the value if actually a value, not a getter / setter.
+ if (!descriptor.get && !descriptor.set) {
+ descriptor.value = handleCopy(object[property], cache);
+ }
+ try {
+ defineProperty(clone, property, descriptor);
+ }
+ catch (error) {
+ // Tee above can fail on node in edge cases, so fall back to the loose assignment.
+ clone[property] = descriptor.value;
+ }
+ }
+ else {
+ // In extra edge cases where the property descriptor cannot be retrived, fall back to
+ // the loose assignment.
+ clone[property] = handleCopy(object[property], cache);
+ }
+ }
+ }
+ }
+ return clone;
+};
+/**
+ * @function getRegExpFlags
+ *
+ * @description
+ * get the flags to apply to the copied regexp
+ *
+ * @param regExp the regexp to get the flags of
+ * @returns the flags for the regexp
+ */
+var getRegExpFlags = function (regExp) {
+ var flags = '';
+ if (regExp.global) {
+ flags += 'g';
+ }
+ if (regExp.ignoreCase) {
+ flags += 'i';
+ }
+ if (regExp.multiline) {
+ flags += 'm';
+ }
+ if (regExp.unicode) {
+ flags += 'u';
+ }
+ if (regExp.sticky) {
+ flags += 'y';
+ }
+ return flags;
+};
+
+// utils
+var isArray = Array.isArray;
+var GLOBAL_THIS = (function () {
+ if (typeof self !== 'undefined') {
+ return self;
+ }
+ if (typeof window !== 'undefined') {
+ return window;
+ }
+ if (typeof global !== 'undefined') {
+ return global;
+ }
+ if (console && console.error) {
+ console.error('Unable to locate global object, returning "this".');
+ }
+})();
+/**
+ * @function copy
+ *
+ * @description
+ * copy an object deeply as much as possible
+ *
+ * If `strict` is applied, then all properties (including non-enumerable ones)
+ * are copied with their original property descriptors on both objects and arrays.
+ *
+ * The object is compared to the global constructors in the `realm` provided,
+ * and the native constructor is always used to ensure that extensions of native
+ * objects (allows in ES2015+) are maintained.
+ *
+ * @param object the object to copy
+ * @param [options] the options for copying with
+ * @param [options.isStrict] should the copy be strict
+ * @param [options.realm] the realm (this) object the object is copied from
+ * @returns the copied object
+ */
+function copy(object, options) {
+ // manually coalesced instead of default parameters for performance
+ var isStrict = !!(options && options.isStrict);
+ var realm = (options && options.realm) || GLOBAL_THIS;
+ var getObjectClone = isStrict
+ ? getObjectCloneStrict
+ : getObjectCloneLoose;
+ /**
+ * @function handleCopy
+ *
+ * @description
+ * copy the object recursively based on its type
+ *
+ * @param object the object to copy
+ * @returns the copied object
+ */
+ var handleCopy = function (object, cache) {
+ if (!object || typeof object !== 'object') {
+ return object;
+ }
+ if (cache.has(object)) {
+ return cache.get(object);
+ }
+ var Constructor = object.constructor;
+ // plain objects
+ if (Constructor === realm.Object) {
+ return getObjectClone(object, realm, handleCopy, cache);
+ }
+ var clone;
+ // arrays
+ if (isArray(object)) {
+ // if strict, include non-standard properties
+ if (isStrict) {
+ return getObjectCloneStrict(object, realm, handleCopy, cache);
+ }
+ var length_1 = object.length;
+ clone = new Constructor();
+ cache.set(object, clone);
+ for (var index = 0; index < length_1; index++) {
+ clone[index] = handleCopy(object[index], cache);
+ }
+ return clone;
+ }
+ // dates
+ if (object instanceof realm.Date) {
+ return new Constructor(object.getTime());
+ }
+ // regexps
+ if (object instanceof realm.RegExp) {
+ clone = new Constructor(object.source, object.flags || getRegExpFlags(object));
+ clone.lastIndex = object.lastIndex;
+ return clone;
+ }
+ // maps
+ if (realm.Map && object instanceof realm.Map) {
+ clone = new Constructor();
+ cache.set(object, clone);
+ object.forEach(function (value, key) {
+ clone.set(key, handleCopy(value, cache));
+ });
+ return clone;
+ }
+ // sets
+ if (realm.Set && object instanceof realm.Set) {
+ clone = new Constructor();
+ cache.set(object, clone);
+ object.forEach(function (value) {
+ clone.add(handleCopy(value, cache));
+ });
+ return clone;
+ }
+ // blobs
+ if (realm.Blob && object instanceof realm.Blob) {
+ return object.slice(0, object.size, object.type);
+ }
+ // buffers (node-only)
+ if (realm.Buffer && realm.Buffer.isBuffer(object)) {
+ clone = realm.Buffer.allocUnsafe
+ ? realm.Buffer.allocUnsafe(object.length)
+ : new Constructor(object.length);
+ cache.set(object, clone);
+ object.copy(clone);
+ return clone;
+ }
+ // arraybuffers / dataviews
+ if (realm.ArrayBuffer) {
+ // dataviews
+ if (realm.ArrayBuffer.isView(object)) {
+ clone = new Constructor(object.buffer.slice(0));
+ cache.set(object, clone);
+ return clone;
+ }
+ // arraybuffers
+ if (object instanceof realm.ArrayBuffer) {
+ clone = object.slice(0);
+ cache.set(object, clone);
+ return clone;
+ }
+ }
+ // if the object cannot / should not be cloned, don't
+ if (
+ // promise-like
+ typeof object.then === 'function' ||
+ // errors
+ object instanceof Error ||
+ // weakmaps
+ (realm.WeakMap && object instanceof realm.WeakMap) ||
+ // weaksets
+ (realm.WeakSet && object instanceof realm.WeakSet)) {
+ return object;
+ }
+ // assume anything left is a custom constructor
+ return getObjectClone(object, realm, handleCopy, cache);
+ };
+ return handleCopy(object, createCache());
+}
+// Adding reference to allow usage in CommonJS libraries compiled using TSC, which
+// expects there to be a default property on the exported object. See
+// [#37](https://github.com/planttheidea/fast-copy/issues/37) for details.
+copy.default = copy;
+/**
+ * @function strictCopy
+ *
+ * @description
+ * copy the object with `strict` option pre-applied
+ *
+ * @param object the object to copy
+ * @param [options] the options for copying with
+ * @param [options.realm] the realm (this) object the object is copied from
+ * @returns the copied object
+ */
+copy.strict = function strictCopy(object, options) {
+ return copy(object, {
+ isStrict: true,
+ realm: options ? options.realm : void 0,
+ });
+};
+
/**
* @license
* Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
@@ -26,7 +770,25 @@ function t(t,e,i,s){var r,o=arguments.length,n=o<3?e:null===s?s=Object.getOwnPro
* subject to an additional IP rights grant found at
* http://polymer.github.io/PATENTS.txt
*/
-const Q="undefined"!=typeof window&&null!=window.customElements&&void 0!==window.customElements.polyfillWrapFlushCallback,tt=(t,e,i=null)=>{for(;e!==i;){const i=e.nextSibling;t.removeChild(e),e=i}},et=`{{lit-${String(Math.random()).slice(2)}}}`,it=`\x3c!--${et}--\x3e`,st=new RegExp(`${et}|${it}`);class rt{constructor(t,e){this.parts=[],this.element=e;const i=[],s=[],r=document.createTreeWalker(e.content,133,null,!1);let o=0,n=-1,a=0;const{strings:l,values:{length:c}}=t;for(;a0;){const e=l[a],i=lt.exec(e)[2],s=i.toLowerCase()+"$lit$",r=t.getAttribute(s);t.removeAttribute(s);const o=r.split(st);this.parts.push({type:"attribute",index:n,name:i,strings:o}),a+=o.length-1}}"TEMPLATE"===t.tagName&&(s.push(t),r.currentNode=t.content)}else if(3===t.nodeType){const e=t.data;if(e.indexOf(et)>=0){const s=t.parentNode,r=e.split(st),o=r.length-1;for(let e=0;e{const i=t.length-e.length;return i>=0&&t.slice(i)===e},nt=t=>-1!==t.index,at=()=>document.createComment(""),lt=/([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F "'>=/]+)([ \x09\x0a\x0c\x0d]*=[ \x09\x0a\x0c\x0d]*(?:[^ \x09\x0a\x0c\x0d"'`<>=]*|"[^"]*|'[^']*))$/;function ct(t,e){const{element:{content:i},parts:s}=t,r=document.createTreeWalker(i,133,null,!1);let o=dt(s),n=s[o],a=-1,l=0;const c=[];let h=null;for(;r.nextNode();){a++;const t=r.currentNode;for(t.previousSibling===h&&(h=null),e.has(t)&&(c.push(t),null===h&&(h=t)),null!==h&&l++;void 0!==n&&n.index===a;)n.index=null!==h?-1:n.index-l,o=dt(s,o),n=s[o]}c.forEach(t=>t.parentNode.removeChild(t))}const ht=t=>{let e=11===t.nodeType?0:1;const i=document.createTreeWalker(t,133,null,!1);for(;i.nextNode();)e++;return e},dt=(t,e=-1)=>{for(let i=e+1;i {
+ while (start !== end) {
+ const n = start.nextSibling;
+ container.removeChild(start);
+ start = n;
+ }
+};
+
/**
* @license
* Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
@@ -40,7 +802,208 @@ const Q="undefined"!=typeof window&&null!=window.customElements&&void 0!==window
* subject to an additional IP rights grant found at
* http://polymer.github.io/PATENTS.txt
*/
-const ut=new WeakMap,pt=t=>(...e)=>{const i=t(...e);return ut.set(i,!0),i},gt=t=>"function"==typeof t&&ut.has(t),ft={},bt={};
+/**
+ * An expression marker with embedded unique key to avoid collision with
+ * possible text in templates.
+ */
+const marker = `{{lit-${String(Math.random()).slice(2)}}}`;
+/**
+ * An expression marker used text-positions, multi-binding attributes, and
+ * attributes with markup-like text values.
+ */
+const nodeMarker = ``;
+const markerRegex = new RegExp(`${marker}|${nodeMarker}`);
+/**
+ * Suffix appended to all bound attribute names.
+ */
+const boundAttributeSuffix = '$lit$';
+/**
+ * An updatable Template that tracks the location of dynamic parts.
+ */
+class Template {
+ constructor(result, element) {
+ this.parts = [];
+ this.element = element;
+ const nodesToRemove = [];
+ const stack = [];
+ // Edge needs all 4 parameters present; IE11 needs 3rd parameter to be null
+ const walker = document.createTreeWalker(element.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;
+ let index = -1;
+ let partIndex = 0;
+ const { strings, values: { length } } = result;
+ while (partIndex < length) {
+ const node = walker.nextNode();
+ if (node === null) {
+ // We've exhausted the content inside a nested template element.
+ // Because we still have parts (the outer for-loop), we know:
+ // - There is a template in the stack
+ // - The walker will find a nextNode outside the template
+ walker.currentNode = stack.pop();
+ continue;
+ }
+ index++;
+ if (node.nodeType === 1 /* Node.ELEMENT_NODE */) {
+ if (node.hasAttributes()) {
+ const attributes = node.attributes;
+ const { length } = 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 correspondence between part index and attribute index.
+ let count = 0;
+ for (let i = 0; i < length; i++) {
+ if (endsWith(attributes[i].name, boundAttributeSuffix)) {
+ count++;
+ }
+ }
+ while (count-- > 0) {
+ // Get the template literal section leading up to the first
+ // expression in this attribute
+ const stringForPart = 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);
+ node.removeAttribute(attributeLookupName);
+ const statics = attributeValue.split(markerRegex);
+ this.parts.push({ type: 'attribute', index, name, strings: statics });
+ partIndex += statics.length - 1;
+ }
+ }
+ if (node.tagName === 'TEMPLATE') {
+ stack.push(node);
+ walker.currentNode = node.content;
+ }
+ }
+ 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++) {
+ let insert;
+ let s = strings[i];
+ if (s === '') {
+ insert = createMarker();
+ }
+ else {
+ const match = lastAttributeNameRegex.exec(s);
+ if (match !== null && endsWith(match[2], boundAttributeSuffix)) {
+ s = s.slice(0, match.index) + match[1] +
+ match[2].slice(0, -boundAttributeSuffix.length) + match[3];
+ }
+ insert = document.createTextNode(s);
+ }
+ parent.insertBefore(insert, 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 });
+ partIndex++;
+ }
+ }
+ }
+ }
+ // Remove text binding nodes after the walk to not disturb the TreeWalker
+ for (const n of nodesToRemove) {
+ n.parentNode.removeChild(n);
+ }
+ }
+}
+const endsWith = (str, suffix) => {
+ const index = str.length - suffix.length;
+ return index >= 0 && str.slice(index) === suffix;
+};
+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#elements-attributes
+ *
+ * " \x09\x0a\x0c\x0d" are HTML space characters:
+ * https://www.w3.org/TR/html5/infrastructure.html#space-characters
+ *
+ * "\0-\x1F\x7F-\x9F" are Unicode control characters, which includes every
+ * space character except " ".
+ *
+ * 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 =
+// eslint-disable-next-line no-control-regex
+/([ \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.
@@ -54,7 +1017,117 @@ const ut=new WeakMap,pt=t=>(...e)=>{const i=t(...e);return ut.set(i,!0),i},gt=t=
* subject to an additional IP rights grant found at
* http://polymer.github.io/PATENTS.txt
*/
-class mt{constructor(t,e,i){this.__parts=[],this.template=t,this.processor=e,this.options=i}update(t){let e=0;for(const i of this.__parts)void 0!==i&&i.setValue(t[e]),e++;for(const t of this.__parts)void 0!==t&&t.commit()}_clone(){const t=Q?this.template.element.content.cloneNode(!0):document.importNode(this.template.element.content,!0),e=[],i=this.template.parts,s=document.createTreeWalker(t,133,null,!1);let r,o=0,n=0,a=s.nextNode();for(;o n.parentNode.removeChild(n));
+}
+const countNodes = (node) => {
+ let count = (node.nodeType === 11 /* Node.DOCUMENT_FRAGMENT_NODE */) ? 0 : 1;
+ const walker = document.createTreeWalker(node, walkerNodeFilter, null, false);
+ while (walker.nextNode()) {
+ count++;
+ }
+ return count;
+};
+const nextActiveIndexInTemplateParts = (parts, startIndex = -1) => {
+ for (let i = startIndex + 1; i < parts.length; i++) {
+ const part = parts[i];
+ if (isTemplatePartActive(part)) {
+ return i;
+ }
+ }
+ return -1;
+};
+/**
+ * Inserts the given node into the Template, optionally before the given
+ * refNode. In addition to inserting the node into the Template, the Template
+ * part indices are updated to match the mutated Template DOM.
+ */
+function insertNodeIntoTemplate(template, node, refNode = null) {
+ const { element: { content }, parts } = template;
+ // If there's no refNode, then put node at end of template.
+ // No part indices need to be shifted in this case.
+ if (refNode === null || refNode === undefined) {
+ content.appendChild(node);
+ return;
+ }
+ const walker = document.createTreeWalker(content, walkerNodeFilter, null, false);
+ let partIndex = nextActiveIndexInTemplateParts(parts);
+ let insertCount = 0;
+ let walkerIndex = -1;
+ while (walker.nextNode()) {
+ walkerIndex++;
+ const walkerNode = walker.currentNode;
+ if (walkerNode === refNode) {
+ insertCount = countNodes(node);
+ refNode.parentNode.insertBefore(node, refNode);
+ }
+ while (partIndex !== -1 && parts[partIndex].index === walkerIndex) {
+ // If we've inserted the node, simply adjust all subsequent parts
+ if (insertCount > 0) {
+ while (partIndex !== -1) {
+ parts[partIndex].index += insertCount;
+ partIndex = nextActiveIndexInTemplateParts(parts, partIndex);
+ }
+ return;
+ }
+ partIndex = nextActiveIndexInTemplateParts(parts, partIndex);
+ }
+ }
+}
+
/**
* @license
* Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
@@ -67,7 +1140,80 @@ class mt{constructor(t,e,i){this.__parts=[],this.template=t,this.processor=e,thi
* 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.trustedTypes&&trustedTypes.createPolicy("lit-html",{createHTML:t=>t}),vt=` ${et} `;class yt{constructor(t,e,i,s){this.strings=t,this.values=e,this.type=i,this.processor=s}getHTML(){const t=this.strings.length-1;let e="",i=!1;for(let s=0;s-1||i)&&-1===t.indexOf("--\x3e",r+1);const o=lt.exec(t);e+=null===o?t+(i?vt:it):t.substr(0,o.index)+o[1]+o[2]+"$lit$"+o[3]+et}return e+=this.strings[t],e}getTemplateElement(){const t=document.createElement("template");let e=this.getHTML();return void 0!==_t&&(e=_t.createHTML(e)),t.innerHTML=e,t}}
+ */
+const directives = new WeakMap();
+/**
+ * Brands a function as a directive factory function so that lit-html will call
+ * the function during template rendering, rather than passing as a value.
+ *
+ * A _directive_ is a function that takes a Part as an argument. It has the
+ * signature: `(part: Part) => void`.
+ *
+ * A directive _factory_ is a function that takes arguments for data and
+ * configuration and returns a directive. Users of directive usually refer to
+ * the directive factory as the directive. For example, "The repeat directive".
+ *
+ * Usually a template author will invoke a directive factory in their template
+ * with relevant arguments, which will then return a directive function.
+ *
+ * Here's an example of using the `repeat()` directive factory that takes an
+ * array and a function to render an item:
+ *
+ * ```js
+ * html`<${repeat(items, (item) => html`- ${item}
`)} `
+ * ```
+ *
+ * When `repeat` is invoked, it returns a directive function that closes over
+ * `items` and the template function. When the outer template is rendered, the
+ * return directive function is called with the Part for the expression.
+ * `repeat` then performs it's custom logic to render multiple items.
+ *
+ * @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)
+ * }
+ * });
+ */
+const directive = (f) => ((...args) => {
+ const d = f(...args);
+ directives.set(d, true);
+ return d;
+});
+const isDirective = (o) => {
+ return typeof o === 'function' && directives.has(o);
+};
+
+/**
+ * @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 = {};
+
/**
* @license
* Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
@@ -80,7 +1226,126 @@ class mt{constructor(t,e,i){this.__parts=[],this.template=t,this.processor=e,thi
* 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 wt=t=>null===t||!("object"==typeof t||"function"==typeof t),St=t=>Array.isArray(t)||!(!t||!t[Symbol.iterator]);class kt{constructor(t,e,i){this.dirty=!0,this.element=t,this.name=e,this.strings=i,this.parts=[];for(let t=0;t{try{const t={get capture(){return Pt=!0,!1}};window.addEventListener("test",t,t),window.removeEventListener("test",t,t)}catch(t){}})();class Et{constructor(t,e,i){this.value=void 0,this.__pendingValue=void 0,this.element=t,this.eventName=e,this.eventContext=i,this.__boundHandleEvent=t=>this.handleEvent(t)}setValue(t){this.__pendingValue=t}commit(){for(;gt(this.__pendingValue);){const t=this.__pendingValue;this.__pendingValue=ft,t(this)}if(this.__pendingValue===ft)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=At(t),this.element.addEventListener(this.eventName,this.__boundHandleEvent,this.__options)),this.value=t,this.__pendingValue=ft}handleEvent(t){"function"==typeof this.value?this.value.call(this.eventContext||this.element,t):this.value.handleEvent(t)}}const At=t=>t&&(Pt?{capture:t.capture,passive:t.passive,once:t.once}:t.capture)
+ */
+/**
+ * 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() {
+ // There are a number of steps in the lifecycle of a template instance's
+ // DOM fragment:
+ // 1. Clone - create the instance fragment
+ // 2. Adopt - adopt into the main document
+ // 3. Process - find part markers and create parts
+ // 4. Upgrade - upgrade custom elements
+ // 5. Update - set node, attribute, property, etc., values
+ // 6. Connect - connect to the document. Optional and outside of this
+ // method.
+ //
+ // We have a few constraints on the ordering of these steps:
+ // * We need to upgrade before updating, so that property values will pass
+ // through any property setters.
+ // * We would like to process before upgrading so that we're sure that the
+ // cloned fragment is inert and not disturbed by self-modifying DOM.
+ // * We want custom elements to upgrade even in disconnected fragments.
+ //
+ // Given these constraints, with full custom elements support we would
+ // prefer the order: Clone, Process, Adopt, Upgrade, Update, Connect
+ //
+ // But Safari does not implement CustomElementRegistry#upgrade, so we
+ // can not implement that order and still have upgrade-before-update and
+ // upgrade disconnected fragments. So we instead sacrifice the
+ // process-before-upgrade constraint, since in Custom Elements v1 elements
+ // must not modify their light DOM in the constructor. We still have issues
+ // when co-existing with CEv0 elements like Polymer 1, and with polyfills
+ // that don't strictly adhere to the no-modification rule because shadow
+ // DOM, which may be created in the constructor, is emulated by being placed
+ // in the light DOM.
+ //
+ // The resulting order is on native is: Clone, Adopt, Upgrade, Process,
+ // Update, Connect. document.importNode() performs Clone, Adopt, and Upgrade
+ // in one step.
+ //
+ // The Custom Elements v1 polyfill supports upgrade(), so the order when
+ // polyfilled is the more ideal: Clone, Process, Adopt, Upgrade, Update,
+ // Connect.
+ const fragment = isCEPolyfill ?
+ this.template.element.content.cloneNode(true) :
+ document.importNode(this.template.element.content, true);
+ const stack = [];
+ const parts = this.template.parts;
+ // 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 partIndex = 0;
+ let nodeIndex = 0;
+ let part;
+ let node = walker.nextNode();
+ // Loop through all the nodes and parts of a template
+ while (partIndex < parts.length) {
+ part = parts[partIndex];
+ if (!isTemplatePartActive(part)) {
+ this.__parts.push(undefined);
+ partIndex++;
+ continue;
+ }
+ // Progress the tree walker until we find our next part's node.
+ // Note that multiple parts may share the same node (attribute parts
+ // on a single element), so this loop may not run at all.
+ while (nodeIndex < part.index) {
+ nodeIndex++;
+ if (node.nodeName === 'TEMPLATE') {
+ stack.push(node);
+ walker.currentNode = node.content;
+ }
+ if ((node = walker.nextNode()) === null) {
+ // We've exhausted the content inside a nested template element.
+ // Because we still have parts (the outer for-loop), we know:
+ // - There is a template in the stack
+ // - The walker will find a nextNode outside the template
+ walker.currentNode = stack.pop();
+ node = walker.nextNode();
+ }
+ }
+ // We've arrived at our part's node.
+ 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++;
+ }
+ if (isCEPolyfill) {
+ document.adoptNode(fragment);
+ customElements.upgrade(fragment);
+ }
+ return fragment;
+ }
+}
+
/**
* @license
* Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
@@ -93,7 +1358,570 @@ class mt{constructor(t,e,i){this.__parts=[],this.template=t,this.processor=e,thi
* 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
- */;function $t(t){let e=Nt.get(t.type);void 0===e&&(e={stringsArray:new WeakMap,keyString:new Map},Nt.set(t.type,e));let i=e.stringsArray.get(t.strings);if(void 0!==i)return i;const s=t.strings.join(et);return i=e.keyString.get(s),void 0===i&&(i=new rt(t,t.getTemplateElement()),e.keyString.set(s,i)),e.stringsArray.set(t.strings,i),i}const Nt=new Map,jt=new WeakMap;
+ */
+/**
+ * Our TrustedTypePolicy for HTML which is declared using the html template
+ * tag function.
+ *
+ * That HTML is a developer-authored constant, and is parsed with innerHTML
+ * before any untrusted expressions have been mixed in. Therefor it is
+ * considered safe by construction.
+ */
+const policy = window.trustedTypes &&
+ trustedTypes.createPolicy('lit-html', { createHTML: (s) => s });
+const commentMarker = ` ${marker} `;
+/**
+ * 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 `` element.
+ */
+ getHTML() {
+ const l = this.strings.length - 1;
+ let html = '';
+ let isCommentBinding = false;
+ for (let i = 0; i < l; i++) {
+ const s = this.strings[i];
+ // For each binding we want to determine the kind of marker to insert
+ // into the template source before it's parsed by the browser's HTML
+ // parser. The marker type is based on whether the expression is in an
+ // attribute, text, or comment position.
+ // * For node-position bindings we insert a comment with the marker
+ // sentinel as its text content, like .
+ // * For attribute bindings we insert just the marker sentinel for the
+ // first binding, so that we support unquoted attribute bindings.
+ // Subsequent bindings can use a comment marker because multi-binding
+ // attributes must be quoted.
+ // * For comment bindings we insert just the marker sentinel so we don't
+ // close the comment.
+ //
+ // The following code scans the template source, but is *not* an HTML
+ // parser. We don't need to track the tree structure of the HTML, only
+ // whether a binding is inside a comment, and if not, if it appears to be
+ // the first binding in an attribute.
+ const commentOpen = s.lastIndexOf('', commentOpen + 1) === -1;
+ // Check to see if we have an attribute-like sequence preceding the
+ // expression. This can match "name=value" like structures in text,
+ // comments, and attribute values, so there can be false-positives.
+ const attributeMatch = lastAttributeNameRegex.exec(s);
+ if (attributeMatch === null) {
+ // We're only in this branch if we don't have a attribute-like
+ // preceding sequence. For comments, this guards against unusual
+ // attribute values like . Cases like
+ // are handled correctly in the attribute branch
+ // below.
+ html += s + (isCommentBinding ? commentMarker : nodeMarker);
+ }
+ else {
+ // For attributes we use just a marker sentinel, and also append a
+ // $lit$ suffix to the name to opt-out of attribute-specific parsing
+ // that IE and Edge do for style and certain SVG attributes.
+ html += s.substr(0, attributeMatch.index) + attributeMatch[1] +
+ attributeMatch[2] + boundAttributeSuffix + attributeMatch[3] +
+ marker;
+ }
+ }
+ html += this.strings[l];
+ return html;
+ }
+ getTemplateElement() {
+ const template = document.createElement('template');
+ let value = this.getHTML();
+ if (policy !== undefined) {
+ // this is secure because `this.strings` is a TemplateStringsArray.
+ // TODO: validate this when
+ // https://github.com/tc39/proposal-array-is-template-object is
+ // implemented.
+ value = policy.createHTML(value);
+ }
+ template.innerHTML = value;
+ return template;
+ }
+}
+
+/**
+ * @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 isPrimitive = (value) => {
+ return (value === null ||
+ !(typeof value === 'object' || typeof value === 'function'));
+};
+const isIterable = (value) => {
+ return Array.isArray(value) ||
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ !!(value && value[Symbol.iterator]);
+};
+/**
+ * Writes attribute values to the DOM for a group of AttributeParts bound to a
+ * single attribute. The value is only set once even if there are multiple parts
+ * for an attribute.
+ */
+class AttributeCommitter {
+ constructor(element, name, strings) {
+ this.dirty = true;
+ this.element = element;
+ this.name = name;
+ this.strings = strings;
+ this.parts = [];
+ for (let i = 0; i < strings.length - 1; i++) {
+ this.parts[i] = this._createPart();
+ }
+ }
+ /**
+ * Creates a single part. Override this to create a differnt type of part.
+ */
+ _createPart() {
+ return new AttributePart(this);
+ }
+ _getValue() {
+ const strings = this.strings;
+ const l = strings.length - 1;
+ const parts = this.parts;
+ // If we're assigning an attribute via syntax like:
+ // attr="${foo}" or attr=${foo}
+ // but not
+ // attr="${foo} ${bar}" or attr="${foo} baz"
+ // then we don't want to coerce the attribute value into one long
+ // string. Instead we want to just return the value itself directly,
+ // so that sanitizeDOMValue can get the actual value rather than
+ // String(value)
+ // The exception is if v is an array, in which case we do want to smash
+ // it together into a string without calling String() on the array.
+ //
+ // This also allows trusted values (when using TrustedTypes) being
+ // assigned to DOM sinks without being stringified in the process.
+ if (l === 1 && strings[0] === '' && strings[1] === '') {
+ const v = parts[0].value;
+ if (typeof v === 'symbol') {
+ return String(v);
+ }
+ if (typeof v === 'string' || !isIterable(v)) {
+ return v;
+ }
+ }
+ let text = '';
+ for (let i = 0; i < l; i++) {
+ text += strings[i];
+ const part = parts[i];
+ if (part !== undefined) {
+ const v = part.value;
+ if (isPrimitive(v) || !isIterable(v)) {
+ text += typeof v === 'string' ? v : String(v);
+ }
+ else {
+ for (const t of v) {
+ text += typeof t === 'string' ? t : String(t);
+ }
+ }
+ }
+ }
+ text += strings[l];
+ return text;
+ }
+ commit() {
+ if (this.dirty) {
+ this.dirty = false;
+ this.element.setAttribute(this.name, this._getValue());
+ }
+ }
+}
+/**
+ * A Part that controls all or part of an attribute value.
+ */
+class AttributePart {
+ constructor(committer) {
+ this.value = undefined;
+ this.committer = committer;
+ }
+ setValue(value) {
+ if (value !== noChange && (!isPrimitive(value) || value !== this.value)) {
+ this.value = value;
+ // If the value is a not a directive, dirty the committer so that it'll
+ // call setAttribute. If the value is a directive, it'll dirty the
+ // committer if it calls setValue().
+ if (!isDirective(value)) {
+ this.committer.dirty = true;
+ }
+ }
+ }
+ commit() {
+ while (isDirective(this.value)) {
+ const directive = this.value;
+ this.value = noChange;
+ directive(this);
+ }
+ if (this.value === noChange) {
+ return;
+ }
+ this.committer.commit();
+ }
+}
+/**
+ * A Part that controls a location within a Node tree. Like a Range, NodePart
+ * has start and end locations and can set and update the Nodes between those
+ * locations.
+ *
+ * NodeParts support several value types: primitives, Nodes, TemplateResults,
+ * as well as arrays and iterables of those types.
+ */
+class NodePart {
+ constructor(options) {
+ this.value = undefined;
+ this.__pendingValue = undefined;
+ this.options = options;
+ }
+ /**
+ * Appends this part into a container.
+ *
+ * This part must be empty, as its contents are not automatically moved.
+ */
+ appendInto(container) {
+ this.startNode = container.appendChild(createMarker());
+ this.endNode = container.appendChild(createMarker());
+ }
+ /**
+ * Inserts this part after the `ref` node (between `ref` and `ref`'s next
+ * sibling). Both `ref` and its next sibling must be static, unchanging nodes
+ * such as those that appear in a literal section of a template.
+ *
+ * This part must be empty, as its contents are not automatically moved.
+ */
+ insertAfterNode(ref) {
+ this.startNode = ref;
+ this.endNode = ref.nextSibling;
+ }
+ /**
+ * Appends this part into a parent part.
+ *
+ * This part must be empty, as its contents are not automatically moved.
+ */
+ appendIntoPart(part) {
+ part.__insert(this.startNode = createMarker());
+ part.__insert(this.endNode = createMarker());
+ }
+ /**
+ * Inserts this part after the `ref` part.
+ *
+ * This part must be empty, as its contents are not automatically moved.
+ */
+ insertAfterPart(ref) {
+ ref.__insert(this.startNode = createMarker());
+ this.endNode = ref.endNode;
+ ref.endNode = this.startNode;
+ }
+ setValue(value) {
+ this.__pendingValue = value;
+ }
+ commit() {
+ if (this.startNode.parentNode === null) {
+ return;
+ }
+ while (isDirective(this.__pendingValue)) {
+ const directive = this.__pendingValue;
+ this.__pendingValue = noChange;
+ directive(this);
+ }
+ const value = this.__pendingValue;
+ if (value === noChange) {
+ return;
+ }
+ if (isPrimitive(value)) {
+ if (value !== this.value) {
+ this.__commitText(value);
+ }
+ }
+ else if (value instanceof TemplateResult) {
+ this.__commitTemplateResult(value);
+ }
+ else if (value instanceof Node) {
+ this.__commitNode(value);
+ }
+ else if (isIterable(value)) {
+ this.__commitIterable(value);
+ }
+ else if (value === nothing) {
+ this.value = nothing;
+ this.clear();
+ }
+ else {
+ // Fallback, will render the string representation
+ this.__commitText(value);
+ }
+ }
+ __insert(node) {
+ this.endNode.parentNode.insertBefore(node, this.endNode);
+ }
+ __commitNode(value) {
+ if (this.value === value) {
+ return;
+ }
+ this.clear();
+ this.__insert(value);
+ this.value = value;
+ }
+ __commitText(value) {
+ const node = this.startNode.nextSibling;
+ value = value == null ? '' : value;
+ // If `value` isn't already a string, we explicitly convert it here in case
+ // it can't be implicitly converted - i.e. it's a symbol.
+ const valueAsString = typeof value === 'string' ? value : String(value);
+ if (node === this.endNode.previousSibling &&
+ node.nodeType === 3 /* Node.TEXT_NODE */) {
+ // If we only have a single text node between the markers, we can just
+ // set its value, rather than replacing it.
+ // TODO(justinfagnani): Can we just check if this.value is primitive?
+ node.data = valueAsString;
+ }
+ else {
+ this.__commitNode(document.createTextNode(valueAsString));
+ }
+ this.value = value;
+ }
+ __commitTemplateResult(value) {
+ const template = this.options.templateFactory(value);
+ if (this.value instanceof TemplateInstance &&
+ this.value.template === template) {
+ this.value.update(value.values);
+ }
+ else {
+ // Make sure we propagate the template processor from the TemplateResult
+ // so that we use its syntax extension, etc. The template factory comes
+ // from the render function options so that it can control template
+ // caching and preprocessing.
+ const instance = new TemplateInstance(template, value.processor, this.options);
+ const fragment = instance._clone();
+ instance.update(value.values);
+ this.__commitNode(fragment);
+ this.value = instance;
+ }
+ }
+ __commitIterable(value) {
+ // For an Iterable, we create a new InstancePart per item, then set its
+ // value to the item. This is a little bit of overhead for every item in
+ // an Iterable, but it lets us recurse easily and efficiently update Arrays
+ // of TemplateResults that will be commonly returned from expressions like:
+ // array.map((i) => html`${i}`), by reusing existing TemplateInstances.
+ // If _value is an array, then the previous render was of an
+ // iterable and _value will contain the NodeParts from the previous
+ // render. If _value is not an array, clear this part and make a new
+ // array for NodeParts.
+ if (!Array.isArray(this.value)) {
+ this.value = [];
+ this.clear();
+ }
+ // Lets us keep track of how many items we stamped so we can clear leftover
+ // items from a previous render
+ const itemParts = this.value;
+ let partIndex = 0;
+ let itemPart;
+ for (const item of value) {
+ // Try to reuse an existing part
+ itemPart = itemParts[partIndex];
+ // If no existing part, create a new one
+ if (itemPart === undefined) {
+ itemPart = new NodePart(this.options);
+ itemParts.push(itemPart);
+ if (partIndex === 0) {
+ itemPart.appendIntoPart(this);
+ }
+ else {
+ itemPart.insertAfterPart(itemParts[partIndex - 1]);
+ }
+ }
+ itemPart.setValue(item);
+ itemPart.commit();
+ partIndex++;
+ }
+ if (partIndex < itemParts.length) {
+ // Truncate the parts array so _value reflects the current state
+ itemParts.length = partIndex;
+ this.clear(itemPart && itemPart.endNode);
+ }
+ }
+ clear(startNode = this.startNode) {
+ removeNodes(this.startNode.parentNode, startNode.nextSibling, this.endNode);
+ }
+}
+/**
+ * Implements a boolean attribute, roughly as defined in the HTML
+ * specification.
+ *
+ * If the value is truthy, then the attribute is present with a value of
+ * ''. If the value is falsey, the attribute is removed.
+ */
+class BooleanAttributePart {
+ constructor(element, name, strings) {
+ this.value = undefined;
+ this.__pendingValue = undefined;
+ if (strings.length !== 2 || strings[0] !== '' || strings[1] !== '') {
+ throw new Error('Boolean attributes can only contain a single expression');
+ }
+ this.element = element;
+ this.name = name;
+ this.strings = strings;
+ }
+ setValue(value) {
+ this.__pendingValue = value;
+ }
+ commit() {
+ while (isDirective(this.__pendingValue)) {
+ const directive = this.__pendingValue;
+ this.__pendingValue = noChange;
+ directive(this);
+ }
+ if (this.__pendingValue === noChange) {
+ return;
+ }
+ const value = !!this.__pendingValue;
+ if (this.value !== value) {
+ if (value) {
+ this.element.setAttribute(this.name, '');
+ }
+ else {
+ this.element.removeAttribute(this.name);
+ }
+ this.value = value;
+ }
+ this.__pendingValue = noChange;
+ }
+}
+/**
+ * Sets attribute values for PropertyParts, so that the value is only set once
+ * even if there are multiple parts for a property.
+ *
+ * If an expression controls the whole property value, then the value is simply
+ * assigned to the property under control. If there are string literals or
+ * multiple expressions, then the strings are expressions are interpolated into
+ * a string first.
+ */
+class PropertyCommitter extends AttributeCommitter {
+ constructor(element, name, strings) {
+ super(element, name, strings);
+ this.single =
+ (strings.length === 2 && strings[0] === '' && strings[1] === '');
+ }
+ _createPart() {
+ return new PropertyPart(this);
+ }
+ _getValue() {
+ if (this.single) {
+ return this.parts[0].value;
+ }
+ return super._getValue();
+ }
+ commit() {
+ if (this.dirty) {
+ this.dirty = false;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ this.element[this.name] = this._getValue();
+ }
+ }
+}
+class PropertyPart extends AttributePart {
+}
+// Detect event listener options support. If the `capture` property is read
+// from the options object, then options are supported. If not, then the third
+// argument to add/removeEventListener is interpreted as the boolean capture
+// value so we should only pass the `capture` property.
+let eventOptionsSupported = false;
+// Wrap into an IIFE because MS Edge <= v41 does not support having try/catch
+// blocks right into the body of a module
+(() => {
+ try {
+ const options = {
+ get capture() {
+ eventOptionsSupported = true;
+ return false;
+ }
+ };
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ window.addEventListener('test', options, options);
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ window.removeEventListener('test', options, options);
+ }
+ catch (_e) {
+ // event options not supported
+ }
+})();
+class EventPart {
+ constructor(element, eventName, eventContext) {
+ this.value = undefined;
+ this.__pendingValue = undefined;
+ this.element = element;
+ this.eventName = eventName;
+ this.eventContext = eventContext;
+ this.__boundHandleEvent = (e) => this.handleEvent(e);
+ }
+ setValue(value) {
+ this.__pendingValue = value;
+ }
+ commit() {
+ while (isDirective(this.__pendingValue)) {
+ const directive = this.__pendingValue;
+ this.__pendingValue = noChange;
+ directive(this);
+ }
+ if (this.__pendingValue === noChange) {
+ return;
+ }
+ const newListener = this.__pendingValue;
+ const oldListener = this.value;
+ const shouldRemoveListener = newListener == null ||
+ oldListener != null &&
+ (newListener.capture !== oldListener.capture ||
+ newListener.once !== oldListener.once ||
+ newListener.passive !== oldListener.passive);
+ const shouldAddListener = newListener != null && (oldListener == null || shouldRemoveListener);
+ if (shouldRemoveListener) {
+ this.element.removeEventListener(this.eventName, this.__boundHandleEvent, this.__options);
+ }
+ if (shouldAddListener) {
+ this.__options = getOptions(newListener);
+ this.element.addEventListener(this.eventName, this.__boundHandleEvent, this.__options);
+ }
+ this.value = newListener;
+ this.__pendingValue = noChange;
+ }
+ handleEvent(event) {
+ if (typeof this.value === 'function') {
+ this.value.call(this.eventContext || this.element, event);
+ }
+ else {
+ this.value.handleEvent(event);
+ }
+ }
+}
+// We copy options because of the inconsistent behavior of browsers when reading
+// the third argument of add/removeEventListener. IE11 doesn't support options
+// at all. Chrome 41 only reads `capture` if the argument is an object.
+const getOptions = (o) => o &&
+ (eventOptionsSupported ?
+ { capture: o.capture, passive: o.passive, once: o.once } :
+ o.capture);
+
/**
* @license
* Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
@@ -106,7 +1934,41 @@ class mt{constructor(t,e,i){this.__parts=[],this.template=t,this.processor=e,thi
* 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 Rt=new
+ */
+/**
+ * The default TemplateFactory which caches Templates keyed on
+ * result.type and result.strings.
+ */
+function templateFactory(result) {
+ let templateCache = templateCaches.get(result.type);
+ if (templateCache === undefined) {
+ templateCache = {
+ stringsArray: new WeakMap(),
+ keyString: new Map()
+ };
+ templateCaches.set(result.type, templateCache);
+ }
+ let template = templateCache.stringsArray.get(result.strings);
+ if (template !== undefined) {
+ return template;
+ }
+ // If the TemplateStringsArray is new, generate a key from the strings
+ // This key is shared between all templates with identical content
+ const key = result.strings.join(marker);
+ // Check if we already have a Template for this key
+ template = templateCache.keyString.get(key);
+ if (template === undefined) {
+ // If we have not seen this key before, create a new Template
+ template = new Template(result, result.getTemplateElement());
+ // Cache the Template for this key
+ templateCache.keyString.set(key, template);
+ }
+ // Cache all future queries for this TemplateStringsArray
+ templateCache.stringsArray.set(result.strings, template);
+ return template;
+}
+const templateCaches = new Map();
+
/**
* @license
* Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
@@ -120,20 +1982,1357 @@ class mt{constructor(t,e,i){this.__parts=[],this.template=t,this.processor=e,thi
* subject to an additional IP rights grant found at
* http://polymer.github.io/PATENTS.txt
*/
-class{handleAttributeExpressions(t,e,i,s){const r=e[0];if("."===r){return new Ct(t,e.slice(1),i).parts}if("@"===r)return[new Et(t,e.slice(1),s.eventContext)];if("?"===r)return[new Tt(t,e.slice(1),i)];return new kt(t,e,i).parts}handleTextExpression(t){return new Ot(t)}};
+const parts = new WeakMap();
+/**
+ * Renders a template result or other value to a container.
+ *
+ * To update a container with new values, reevaluate the template literal and
+ * call `render` with the new result.
+ *
+ * @param result Any value renderable by NodePart - typically a TemplateResult
+ * created by evaluating a template tag like `html` or `svg`.
+ * @param container A DOM parent to render to. The entire contents are either
+ * replaced, or efficiently updated if the same result type was previous
+ * rendered there.
+ * @param options RenderOptions for the entire render tree rendered to this
+ * container. Render options must *not* change between renders to the same
+ * container, as those changes will not effect previously rendered DOM.
+ */
+const render$1 = (result, container, options) => {
+ let part = parts.get(container);
+ if (part === undefined) {
+ removeNodes(container, container.firstChild);
+ parts.set(container, part = new NodePart(Object.assign({ templateFactory }, options)));
+ part.appendInto(container);
+ }
+ part.setValue(result);
+ part.commit();
+};
+
+/**
+ * @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
+ */
+/**
+ * Creates Parts when a template is instantiated.
+ */
+class DefaultTemplateProcessor {
+ /**
+ * Create parts for an attribute-position binding, given the event, attribute
+ * name, and string literals.
+ *
+ * @param element The element containing the binding
+ * @param name The attribute name
+ * @param strings The string literals. There are always at least two strings,
+ * event for fully-controlled bindings with a single expression.
+ */
+ handleAttributeExpressions(element, name, strings, options) {
+ const prefix = name[0];
+ if (prefix === '.') {
+ const committer = new PropertyCommitter(element, name.slice(1), strings);
+ return committer.parts;
+ }
+ if (prefix === '@') {
+ return [new EventPart(element, name.slice(1), options.eventContext)];
+ }
+ if (prefix === '?') {
+ return [new BooleanAttributePart(element, name.slice(1), strings)];
+ }
+ const committer = new AttributeCommitter(element, name, strings);
+ return committer.parts;
+ }
+ /**
+ * Create parts for a text-position binding.
+ * @param templateFactory
+ */
+ handleTextExpression(options) {
+ return new NodePart(options);
+ }
+}
+const defaultTemplateProcessor = new DefaultTemplateProcessor();
+
+/**
+ * @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
+ */
+// IMPORTANT: do not change the property name or the assignment expression.
+// This line will be used in regexes to search for lit-html usage.
+// TODO(justinfagnani): inject version number at build time
+if (typeof window !== 'undefined') {
+ (window['litHtmlVersions'] || (window['litHtmlVersions'] = [])).push('1.4.1');
+}
+/**
+ * Interprets a template literal as an HTML template that can efficiently
+ * render to and update a container.
+ */
+const html = (strings, ...values) => new TemplateResult(strings, values, 'html', defaultTemplateProcessor);
+
+/**
+ * @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
+ */
+// Get a key to lookup in `templateCaches`.
+const getTemplateCacheKey = (type, scopeName) => `${type}--${scopeName}`;
+let compatibleShadyCSSVersion = true;
+if (typeof window.ShadyCSS === 'undefined') {
+ compatibleShadyCSSVersion = false;
+}
+else if (typeof window.ShadyCSS.prepareTemplateDom === 'undefined') {
+ console.warn(`Incompatible ShadyCSS version detected. ` +
+ `Please update to at least @webcomponents/webcomponentsjs@2.0.2 and ` +
+ `@webcomponents/shadycss@1.3.1.`);
+ compatibleShadyCSSVersion = false;
+}
+/**
+ * Template factory which scopes template DOM using ShadyCSS.
+ * @param scopeName {string}
+ */
+const shadyTemplateFactory = (scopeName) => (result) => {
+ const cacheKey = getTemplateCacheKey(result.type, scopeName);
+ let templateCache = templateCaches.get(cacheKey);
+ if (templateCache === undefined) {
+ templateCache = {
+ stringsArray: new WeakMap(),
+ keyString: new Map()
+ };
+ templateCaches.set(cacheKey, templateCache);
+ }
+ let template = templateCache.stringsArray.get(result.strings);
+ if (template !== undefined) {
+ return template;
+ }
+ const key = result.strings.join(marker);
+ template = templateCache.keyString.get(key);
+ if (template === undefined) {
+ const element = result.getTemplateElement();
+ if (compatibleShadyCSSVersion) {
+ window.ShadyCSS.prepareTemplateDom(element, scopeName);
+ }
+ template = new Template(result, element);
+ templateCache.keyString.set(key, template);
+ }
+ templateCache.stringsArray.set(result.strings, template);
+ return template;
+};
+const TEMPLATE_TYPES = ['html', 'svg'];
+/**
+ * Removes all style elements from Templates for the given scopeName.
+ */
+const removeStylesFromLitTemplates = (scopeName) => {
+ TEMPLATE_TYPES.forEach((type) => {
+ const templates = templateCaches.get(getTemplateCacheKey(type, scopeName));
+ if (templates !== undefined) {
+ templates.keyString.forEach((template) => {
+ const { element: { content } } = template;
+ // IE 11 doesn't support the iterable param Set constructor
+ const styles = new Set();
+ Array.from(content.querySelectorAll('style')).forEach((s) => {
+ styles.add(s);
+ });
+ removeNodesFromTemplate(template, styles);
+ });
+ }
+ });
+};
+const shadyRenderSet = new Set();
+/**
+ * For the given scope name, ensures that ShadyCSS style scoping is performed.
+ * This is done just once per scope name so the fragment and template cannot
+ * be modified.
+ * (1) extracts styles from the rendered fragment and hands them to ShadyCSS
+ * to be scoped and appended to the document
+ * (2) removes style elements from all lit-html Templates for this scope name.
+ *
+ * Note, | | |