diff --git a/src/panels/lovelace/entity-rows/hui-media-player-entity-row.js b/src/panels/lovelace/entity-rows/hui-media-player-entity-row.js
deleted file mode 100644
index c123618852..0000000000
--- a/src/panels/lovelace/entity-rows/hui-media-player-entity-row.js
+++ /dev/null
@@ -1,165 +0,0 @@
-import "@polymer/paper-icon-button/paper-icon-button";
-import { html } from "@polymer/polymer/lib/utils/html-tag";
-import { PolymerElement } from "@polymer/polymer/polymer-element";
-
-import "../components/hui-generic-entity-row";
-
-import LocalizeMixin from "../../../mixins/localize-mixin";
-
-const SUPPORT_PAUSE = 1;
-const SUPPORT_NEXT_TRACK = 32;
-const SUPPORTS_PLAY = 16384;
-const OFF_STATES = ["off", "idle"];
-
-/*
- * @appliesMixin LocalizeMixin
- */
-class HuiMediaPlayerEntityRow extends LocalizeMixin(PolymerElement) {
- static get template() {
- return html`
- ${this.styleTemplate}
-
- ${this.mediaPlayerControlTemplate}
-
- `;
- }
-
- static get styleTemplate() {
- return html`
-
- `;
- }
-
- static get mediaPlayerControlTemplate() {
- return html`
-
-
-
-
- [[_computeState(_stateObj.state)]]
-
-
-
[[_computeMediaTitle(_stateObj)]]
- `;
- }
-
- static get properties() {
- return {
- hass: Object,
- _config: Object,
- _stateObj: {
- type: Object,
- computed: "_computeStateObj(hass.states, _config.entity)",
- },
- };
- }
-
- _computeStateObj(states, entityId) {
- return states && entityId in states ? states[entityId] : null;
- }
-
- setConfig(config) {
- if (!config || !config.entity) {
- throw new Error("Entity not configured.");
- }
- this._config = config;
- }
-
- _computeControlIcon(stateObj) {
- if (!stateObj) return null;
-
- if (stateObj.state !== "playing") {
- return stateObj.attributes.supported_features & SUPPORTS_PLAY
- ? "hass:play"
- : "";
- }
-
- return stateObj.attributes.supported_features & SUPPORT_PAUSE
- ? "hass:pause"
- : "hass:stop";
- }
-
- _computeMediaTitle(stateObj) {
- if (!stateObj || this._isOff(stateObj.state)) return null;
-
- let prefix;
- let suffix;
-
- switch (stateObj.attributes.media_content_type) {
- case "music":
- prefix = stateObj.attributes.media_artist;
- suffix = stateObj.attributes.media_title;
- break;
- case "tvshow":
- prefix = stateObj.attributes.media_series_title;
- suffix = stateObj.attributes.media_title;
- break;
- default:
- prefix =
- stateObj.attributes.media_title ||
- stateObj.attributes.app_name ||
- stateObj.state;
- suffix = "";
- }
-
- return prefix && suffix ? `${prefix}: ${suffix}` : prefix || suffix || "";
- }
-
- _computeState(state) {
- return (
- this.localize(`state.media_player.${state}`) ||
- this.localize(`state.default.${state}`) ||
- state
- );
- }
-
- _callService(service) {
- this.hass.callService("media_player", service, {
- entity_id: this._config.entity,
- });
- }
-
- _playPause(event) {
- event.stopPropagation();
- this._callService("media_play_pause");
- }
-
- _nextTrack(event) {
- event.stopPropagation();
- if (this._stateObj.attributes.supported_features & SUPPORT_NEXT_TRACK) {
- this._callService("media_next_track");
- }
- }
-
- _isOff(state) {
- return OFF_STATES.includes(state);
- }
-
- _supportsNext(stateObj) {
- return (
- stateObj && stateObj.attributes.supported_features & SUPPORT_NEXT_TRACK
- );
- }
-}
-customElements.define("hui-media-player-entity-row", HuiMediaPlayerEntityRow);
diff --git a/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts b/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts
new file mode 100644
index 0000000000..10c3860b67
--- /dev/null
+++ b/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts
@@ -0,0 +1,171 @@
+import { html, LitElement } from "@polymer/lit-element";
+import { TemplateResult } from "lit-html";
+import "@polymer/paper-icon-button/paper-icon-button";
+
+import "../components/hui-generic-entity-row";
+
+import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
+import { EntityRow, EntityConfig } from "./types";
+import { HomeAssistant } from "../../../types";
+import { HassEntity } from "home-assistant-js-websocket";
+
+const SUPPORT_PAUSE = 1;
+const SUPPORT_NEXT_TRACK = 32;
+const SUPPORTS_PLAY = 16384;
+const OFF_STATES = ["off", "idle"];
+
+class HuiMediaPlayerEntityRow extends hassLocalizeLitMixin(LitElement)
+ implements EntityRow {
+ public hass?: HomeAssistant;
+ private _config?: EntityConfig;
+
+ static get properties() {
+ return {
+ hass: {},
+ _config: {},
+ };
+ }
+
+ public setConfig(config: EntityConfig): void {
+ if (!config || !config.entity) {
+ throw new Error("Invalid Configuration: 'entity' required");
+ }
+
+ this._config = config;
+ }
+
+ protected render(): TemplateResult {
+ if (!this.hass || !this._config) {
+ return html``;
+ }
+
+ const stateObj = this.hass.states[this._config.entity];
+
+ if (!stateObj) {
+ return html`
+
+ `;
+ }
+
+ const supportsPlay =
+ // tslint:disable-next-line:no-bitwise
+ stateObj.attributes.supported_features! & SUPPORTS_PLAY;
+ const supportsNext =
+ // tslint:disable-next-line:no-bitwise
+ stateObj.attributes.supported_features! & SUPPORT_NEXT_TRACK;
+
+ return html`
+ ${this.renderStyle()}
+
+ ${
+ OFF_STATES.includes(stateObj.state)
+ ? html`
+
+ ${
+ this.localize(`state.media_player.${stateObj.state}`) ||
+ this.localize(`state.default.${stateObj.state}`) ||
+ stateObj.state
+ }
+
+ `
+ : html`
+
+ ${
+ stateObj.state !== "playing" && !supportsPlay
+ ? ""
+ : html`
+
+ `
+ }
+ ${
+ supportsNext
+ ? html`
+
+ `
+ : ""
+ }
+
+ ${this._computeMediaTitle(stateObj)}
+ `
+ }
+
+ `;
+ }
+
+ private renderStyle(): TemplateResult {
+ return html`
+
+ `;
+ }
+
+ private _computeControlIcon(stateObj: HassEntity): string {
+ if (stateObj.state !== "playing") {
+ return "hass:play";
+ }
+
+ // tslint:disable-next-line:no-bitwise
+ return stateObj.attributes.supported_features! & SUPPORT_PAUSE
+ ? "hass:pause"
+ : "hass:stop";
+ }
+
+ private _computeMediaTitle(stateObj: HassEntity): string {
+ let prefix;
+ let suffix;
+
+ switch (stateObj.attributes.media_content_type) {
+ case "music":
+ prefix = stateObj.attributes.media_artist;
+ suffix = stateObj.attributes.media_title;
+ break;
+ case "tvshow":
+ prefix = stateObj.attributes.media_series_title;
+ suffix = stateObj.attributes.media_title;
+ break;
+ default:
+ prefix =
+ stateObj.attributes.media_title ||
+ stateObj.attributes.app_name ||
+ stateObj.state;
+ suffix = "";
+ }
+
+ return prefix && suffix ? `${prefix}: ${suffix}` : prefix || suffix || "";
+ }
+
+ private _playPause(): void {
+ this.hass!.callService("media_player", "media_play_pause", {
+ entity_id: this._config!.entity,
+ });
+ }
+
+ private _nextTrack(): void {
+ this.hass!.callService("media_player", "media_next_track", {
+ entity_id: this._config!.entity,
+ });
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "hui-media-player-entity-row": HuiMediaPlayerEntityRow;
+ }
+}
+
+customElements.define("hui-media-player-entity-row", HuiMediaPlayerEntityRow);