Skip to content

Instantly share code, notes, and snippets.

@akc42
Created January 4, 2019 16:52
Show Gist options
  • Save akc42/855b902f1e5c3dabb7e5d743d9710ea1 to your computer and use it in GitHub Desktop.
Save akc42/855b902f1e5c3dabb7e5d743d9710ea1 to your computer and use it in GitHub Desktop.
Custom Input using Decorator Pattern.
import { LitElement, html } from '../../node_modules/@polymer/lit-element/lit-element.js';
import {ifDefined} from '../../node_modules/lit-html/directives/if-defined.js';
import {classMap} from '../../node_modules/lit-html/directives/class-map.js';
import {render} from '../../node_modules/lit-html/lib/shady-render.js';
let inputCounter = 0;
class CustomInput extends LitElement {
static get properties() {
return {
label: {type: String},
disabled: {type: Boolean},
invalid: {type: Boolean, reflect: true},
title: {type: String},
type: {type: String},
pattern: {type: String},
placeholder: {type: String},
autocomplete: {type: String},
autofocus: {type: Boolean},
form: {type: String},
list: {type: String},
name: {type: String},
readonly: {type: Boolean},
required: {type: Boolean},
value: {type: String},
max: {type: Number},
min: {type: Number},
step: {type: Number},
message:{type: String},
_placeholder: {type: String},
validator: {type: Function}
};
}
constructor() {
super();
this.label = '';
this.name = '';
this.type='text';
this.disabled = false;
this.autofocus = false;
this.readonly = false;
this.required = false;
this.value = '';
this.invalid = false;
this.message = '';
this._placeholder = this.label; //only for now
this.inputid = 'custom-input-id-' + inputCounter++;
this._inputChanged = this._inputChanged.bind(this);
}
connectedCallback() {
super.connectedCallback();
if (this.input === undefined) {
this.renderInput();
this.input = this.querySelector('#' + this.id);
}
}
update(changed) {
if (changed.has('placeholder') || changed.has('label')) {
this._placeholder = this.placeholder || this.label;
}
if (changed.has('value') && changed.get('value') !== undefined) {
this.dispatchEvent(new CustomEvent('value-changed'));
}
super.update();
}
render() {
this.renderInput();
return html`
<style>
:host {
display: block;
}
::slotted(input) {
border-left: none;
border-right: none;
border-top: none;
border-bottom: 1px solid grey;
position: relative;
font-family: Roboto, sans-serif;
padding: 2px 0;
margin-bottom: 10px;
}
::slotted(input:focus) {
border-bottom-color: var(--pas-input-focus-colour, blue);
outline: none;
}
::slotted(input.error), ::slotted(input:focus.error) {
border-bottom-color: red;
}
.error {
color: red;
}
div.errorcontainer {
position: relative
}
div.error {
position: absolute;
left: 2px;
top: -10px;
font-size: 8pt;
}
label {
display:block;
transform: translate(5px, 20px);
transition: 0.5s ease-in-out;
font-size: 8pt;
}
label.inplace {
transform: translate(0,0);
font-size: 10pt;
}
</style>
<label id="label" for=${this.inputid} class=${classMap({
inplace: this.placeholder !== undefined || this.value.length > 0,
error: this.invalid
})}>${this.label}</label>
<slot name=${this.inputid}></slot>
<div class="errorcontainer">
${this.invalid ? html`<div class="error">${this.message}</div>` : ''}
</div>
`;
}
renderInput() {
render(this.inputTemplate(), this, this.localName);
}
inputTemplate() {
return html`
<input
id="${this.inputid}"
slot=${this.inputid}
class="${classMap({error: this.invalid})}"
type=${this.type}
aria-labelledby="label"
?disabled=${this.disabled}
title=${ifDefined(this.title)}
pattern=${ifDefined(this.pattern)}
placeholder=${this._placeholder}
autocomplete=${ifDefined(this.autocomplete)}
?autofocus=${this.autofocus}
form=${ifDefined(this.form)}
list=${ifDefined(this.list)}
name=${this.name}
?readonly=${this.readonly}
?required=${this.required}
value=${this.value}
max=${ifDefined(this.max)}
min=${ifDefined(this.min)}
step=${ifDefined(this.step)}
@input=${this._inputChanged}
/>
`;
}
validate() {
if (typeof this.validator === 'function' ) {
return this.validator(this.value);
}
return !this.invalid;
}
_inputChanged(e) {
e.stopPropagation();
if (this.value !== e.target.value) {
this.invalid = false;
this.value = e.target.value;
}
}
}
customElements.define('custom-input', CustomInput);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment