Extract time-unit component. Refactor styles. Refactor error partial.

This commit is contained in:
2020-05-05 02:47:04 +03:00
parent 1a827de177
commit fdc9c5bd22
6 changed files with 156 additions and 119 deletions
+109
View File
@@ -0,0 +1,109 @@
import {
css,
CSSResult,
customElement,
html,
LitElement,
property,
TemplateResult,
} from 'lit-element';
import { TimeUnit } from '../models';
import { Direction } from '../types';
@customElement('time-unit')
export class TimeUnitComponent extends LitElement {
@property() private unit?: TimeUnit;
render(): TemplateResult {
if (!this.unit) {
throw new Error('Missing unit in time-unit. This should never happen :)');
}
return html`<div class="time-unit">
${this.renderStepChanger(Direction.UP)}
<input
class="time-input"
type="number"
placeholder="MM"
min="0"
max="60"
.value="${this.unit.toString()}"
@change=${this.onInputChange}
/>
${this.renderStepChanger(Direction.DOWN)}
</div>`;
}
onInputChange({ target: { value } }: { target: HTMLInputElement }): void {
this.unit!.setStringValue(value);
this.emitUpdate();
}
onStepChangerClick(direction: Direction): void {
this.unit!.stepUpdate(direction);
this.emitUpdate();
}
private emitUpdate(): void {
const event = new CustomEvent('update');
this.dispatchEvent(event);
}
private renderStepChanger(direction: Direction): TemplateResult {
return html`
<div class="time-picker-icon" @click=${() => this.onStepChangerClick(direction)}>
<ha-icon .icon="mdi:arrow-${direction}"></ha-icon>
<mwc-ripple id="ripple"></mwc-ripple>
</div>
`;
}
static get styles(): CSSResult {
return css`
.time-unit {
display: flex;
flex-direction: column;
align-items: center;
padding: 0 8px;
}
.time-picker-icon {
width: 30px;
padding: 8px;
text-align: center;
cursor: pointer;
}
.time-input {
width: 30px;
padding: 8px 8px 6px;
background: var(--time-picker-card-background-color);
border: 0;
border-bottom: 2px solid var(--time-picker-card-background-color);
color: var(--text-color, #fff);
text-align: center;
font-size: 1em;
-moz-appearance: textfield;
transition: border-color 0.2s ease-in-out;
}
.time-input:focus {
outline: none;
}
.time-input:invalid {
box-shadow: none;
outline: none;
border: 0;
border-bottom: 2px solid red;
}
.time-input::-webkit-inner-spin-button,
.time-input::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
`;
}
}
+4
View File
@@ -1,3 +1,7 @@
import * as pkg from '../package.json'; import * as pkg from '../package.json';
export const CARD_VERSION = pkg.version; export const CARD_VERSION = pkg.version;
export const STYLE_VARIABLES = {
'--time-picker-card-background-color': 'rgb(37, 47, 68)',
};
+10 -45
View File
@@ -1,51 +1,16 @@
import { html, TemplateResult } from 'lit-element'; import { html, TemplateResult } from 'lit-element';
import { TimePickerCardConfig, Direction } from './types'; import { TimePickerCardConfig } from './types';
import { TimeUnit } from './models'; import { LovelaceCard } from 'custom-card-helpers';
export class Partial { export class Partial {
static unit(unit: TimeUnit, serviceFn: () => Promise<void>): TemplateResult {
const onInputChange = ({ target: { value } }: { target: HTMLInputElement }): void => {
unit.setStringValue(value);
serviceFn();
};
return html`
<div class="time-unit">
${Partial.stepChanger(Direction.UP, unit, serviceFn)}
<input
class="time-input"
type="number"
placeholder="MM"
min="0"
max="60"
.value="${unit.toString()}"
@change=${onInputChange}
/>
${Partial.stepChanger(Direction.DOWN, unit, serviceFn)}
</div>
`;
}
private static stepChanger(
direction: Direction,
unit: TimeUnit,
serviceFn: () => Promise<void>
): TemplateResult {
const onIconClick = (): void => {
unit.stepUpdate(direction);
serviceFn();
};
return html`
<div class="time-picker-icon" @click=${onIconClick}>
<ha-icon .icon="mdi:arrow-${direction}"></ha-icon>
<mwc-ripple id="ripple"></mwc-ripple>
</div>
`;
}
static error(error: string, origConfig: TimePickerCardConfig): TemplateResult { static error(error: string, origConfig: TimePickerCardConfig): TemplateResult {
const config = { error, origConfig }; const errorCard = document.createElement('hui-error-card') as LovelaceCard;
return html`<hui-error-card ._config="${config}"></hui-error-card>`; errorCard.setConfig({
type: 'error',
error,
origConfig,
});
return html`${errorCard}`;
} }
} }
-60
View File
@@ -1,60 +0,0 @@
import { css } from 'lit-element';
export const styleVariables = {
'--time-picker-card-background-color': 'rgb(37, 47, 68)',
};
export const styles = css`
.time-picker-ha-card {
padding: 16px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.time-unit {
display: flex;
flex-direction: column;
align-items: center;
padding: 0 8px;
}
.time-picker-icon {
width: 30px;
padding: 8px;
text-align: center;
cursor: pointer;
}
.time-input {
width: 30px;
padding: 8px;
background: var(--time-picker-card-background-color);
border: 0;
color: var(--text-color, #fff);
text-align: center;
font-size: 1em;
}
input[type='number']::-webkit-inner-spin-button,
input[type='number']::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type='number'] {
-moz-appearance: textfield;
}
input[type='number']:focus {
outline: none;
}
input[type='number']:invalid {
box-shadow: none;
outline: none;
border: 0;
border-bottom: 2px solid red;
}
`;
+30 -13
View File
@@ -1,10 +1,18 @@
import { HomeAssistant } from 'custom-card-helpers'; import { HomeAssistant } from 'custom-card-helpers';
import { HassEntity } from 'home-assistant-js-websocket'; import { HassEntity } from 'home-assistant-js-websocket';
import { CSSResult, customElement, html, LitElement, property, TemplateResult } from 'lit-element'; import {
import { CARD_VERSION } from './const'; css,
CSSResult,
customElement,
html,
LitElement,
property,
TemplateResult,
} from 'lit-element';
import './components/time-unit';
import { CARD_VERSION, STYLE_VARIABLES } from './const';
import { Hour, Minute } from './models'; import { Hour, Minute } from './models';
import { Partial } from './partials'; import { Partial } from './partials';
import { styles, styleVariables } from './styles';
import { TimePickerCardConfig } from './types'; import { TimePickerCardConfig } from './types';
console.info( console.info(
@@ -20,6 +28,14 @@ export class TimePickerCard extends LitElement {
@property() private hour?: Hour; @property() private hour?: Hour;
@property() private minute?: Minute; @property() private minute?: Minute;
connectedCallback(): void {
super.connectedCallback();
Object.entries(STYLE_VARIABLES).forEach(([variable, value]) =>
this.style.setProperty(variable, value)
);
}
private get entity(): HassEntity | undefined { private get entity(): HassEntity | undefined {
if (!this.config) { if (!this.config) {
return; return;
@@ -44,15 +60,14 @@ export class TimePickerCard extends LitElement {
); );
} }
this.setStyleVarialbes();
this.hour = new Hour(this.entity?.attributes.hour ?? 0, this.config.hour_step); this.hour = new Hour(this.entity?.attributes.hour ?? 0, this.config.hour_step);
this.minute = new Minute(this.entity?.attributes.minute ?? 0, this.config.minute_step); this.minute = new Minute(this.entity?.attributes.minute ?? 0, this.config.minute_step);
return html` return html`
<ha-card class="time-picker-ha-card"> <ha-card class="time-picker-ha-card">
${Partial.unit(this.hour, this.serviceFn.bind(this))} <time-unit .unit=${this.hour} @update=${this.serviceFn.bind(this)}></time-unit>
<div class="time-separator">:</div> <div class="time-separator">:</div>
${Partial.unit(this.minute, this.serviceFn.bind(this))} <time-unit .unit=${this.minute} @update=${this.serviceFn.bind(this)}></time-unit>
</ha-card> </ha-card>
`; `;
} }
@@ -86,13 +101,15 @@ export class TimePickerCard extends LitElement {
}); });
} }
private setStyleVarialbes(): void {
Object.entries(styleVariables).forEach(([variable, value]) =>
this.style.setProperty(variable, value)
);
}
static get styles(): CSSResult { static get styles(): CSSResult {
return styles; return css`
.time-picker-ha-card {
padding: 16px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
`;
} }
} }
+3 -1
View File
@@ -1,4 +1,6 @@
export interface TimePickerCardConfig { import { LovelaceCardConfig } from 'custom-card-helpers';
export interface TimePickerCardConfig extends LovelaceCardConfig {
entity: string; entity: string;
hour_step?: number; hour_step?: number;
minute_step?: number; minute_step?: number;