Skip to content

Instantly share code, notes, and snippets.

@andreasvirkus
Created November 23, 2018 10:27
Show Gist options
  • Save andreasvirkus/dee66d7963621ea46385a3f8b4920fa6 to your computer and use it in GitHub Desktop.
Save andreasvirkus/dee66d7963621ea46385a3f8b4920fa6 to your computer and use it in GitHub Desktop.
Basic (and with a bit of a buggy UX) date mask input for Vue
<template>
<div
class="q-date-mask"
@keyup.capture="updateValue">
<input
v-if="showDay"
ref="day"
v-model="day"
class="q-date-mask__input q-date-mask__input--day"
type="number"
placeholder="dd"
@input="updateDay"
@blur="day = day.padStart(2, 0)">
<span
v-if="showDay && showMonth"
class="q-date-mask__divider">/</span>
<input
v-if="showMonth"
ref="month"
v-model="month"
class="q-date-mask__input q-date-mask__input--month"
type="number"
placeholder="mm"
@input="updateMonth"
@blur="month = month.padStart(2, 0)">
<span
v-if="showYear && (showDay || showMonth)"
class="q-date-mask__divider">/</span>
<input
v-if="showYear"
ref="year"
v-model="year"
class="q-date-mask__input q-date-mask__input--year"
type="number"
placeholder="yyyy"
@blur="year = year.padStart(4, 0)">
</div>
</template>
<script>
// TODO: If month is greater than 12, keep "1" and move 3 to year?
// TODO: Limit year value to current year, if a prop dictates it
export default {
name: 'q-date-mask',
props: {
value: {
type: [Number, String],
required: true
},
showDay: {
type: Boolean,
default: true
},
showMonth: {
type: Boolean,
default: true
},
showYear: {
type: Boolean,
default: true
}
},
data () {
return {
day: `${this.value ? new Date(this.value).getDate() : ``}`,
month: `${this.value ? new Date(this.value).getMonth() + 1 : ``}`,
year: `${this.value ? new Date(this.value).getFullYear() : ``}`
}
},
watch: {
year (current, prev) {
if (current > 9999) this.year = prev
}
},
methods: {
updateDay () {
if (!this.day.length || parseInt(this.day, 10) < 4) return
if (this.showMonth) this.$refs.month.select()
else if (this.showYear) this.$refs.year.select()
},
updateMonth () {
if (!this.month.length || parseInt(this.month, 10) < 2) return
if (this.showYear) this.$refs.year.select()
},
updateValue () {
const timestamp = Date.parse(`${this.year.padStart(4, 0)}-${this.month}-${this.day}`)
if (Number.isNaN(timestamp)) return
this.$emit(`input`, timestamp)
}
}
}
</script>
<style lang="scss">
.q-date-mask {
$spacing: 0.5rem;
display: inline-flex;
border-radius: .25rem;
border: 1px solid #E8E8E8;
// padding: .5rem;
color: #35495E;
font-size: .825rem;
// 1. Hide the spinner button in Chrome, Safari and Firefox.
&__input {
padding: $spacing;
padding-right: $spacing / 2;
padding-left: $spacing / 2;
border: none;
text-align: center;
/* stylelint-disable-next-line property-no-vendor-prefix */
-moz-appearance: textfield; // 1
&::-webkit-inner-spin-button {
display: none; // 1
}
&:focus {
outline: none;
}
&--day,
&--month {
width: 3em;
}
&--year {
width: 4em;
}
}
&__divider {
padding-top: $spacing * 1.25;
padding-bottom: $spacing;
pointer-events: none;
}
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment