JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.0-beta.4/vue.min.js"></script>
<div id="app">
<h4>{{ search }}</h4>
<textfield v-model="search" placeholder="Search"></textfield>
<textfield v-model="search" placeholder="Search" lazy></textfield>
</div>
CSS
body {
padding: 15px;
}
.textfield {
border-bottom: 1px solid #c1c3d0;
margin-bottom: 15px;
}
.textfield hr {
position: relative;
top: 1px;
margin: 0;
border: 1px solid #17e5ff;
transition: transform .3s cubic-bezier(0.23, 1, 0.32, 1);
transform: scaleX(0);
}
.textfield.is-floating hr {
transform: scaleX(1);
}
.textfield-control {
width: 100%;
padding: 15px;
border: 0;
font-size: 18px;
outline: none;
}
JavaScript
// npm i debounce
function debounce(func, wait, immediate){
var timeout, args, context, timestamp, result;
if (null == wait) wait = 100;
function later() {
var last = Date.now() - timestamp;
if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last);
} else {
timeout = null;
if (!immediate) {
result = func.apply(context, args);
if (!timeout) context = args = null;
}
}
};
var debounced = function(){
context = this;
args = arguments;
timestamp = Date.now();
var callNow = immediate && !timeout;
if (!timeout) timeout = setTimeout(later, wait);
if (callNow) {
result = func.apply(context, args);
context = args = null;
}
return result;
};
debounced.clear = function() {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
};
return debounced;
}
Vue.component('textfield', {
props: {
value: String,
placeholder: String,
inputClass: String,
debounce: {
type: [String, Number],
default: 0,
},
lazy: {
type: Boolean,
default: false,
},
textarea: {
type: Boolean,
default: false,
},
},
computed: {
isDirty() {
return this.value !== '';
},
},
data() {
return {
isFocused: false,
};
},
created() {
const debounceTime = parseInt(this.debounce, 10) || 0;
if (debounceTime > 0) {
this.debouncedEmit = debounce(this.debouncedEmit, debounceTime);
}
},
methods: {
setFocused(e) {
this.isFocused = e.type === 'focus';
},
onInput(e) {
const value = e.target.value;
if (value) {
this.debouncedEmit(value);
} else {
this.$emit('input', value);
}
},
debouncedEmit(value) {
this.$emit('input', value);
},
},
render(createElement) {
const inputEvent = this.lazy === true ? 'change' : 'input';
const isTextarea = this.textarea...