Update Node_modules
This commit is contained in:
+13
@@ -11,6 +11,7 @@
|
||||
:icon-pack="iconPack"
|
||||
:maxlength="maxlength"
|
||||
:autocomplete="newAutocomplete"
|
||||
:use-html5-validation="useHtml5Validation"
|
||||
v-bind="$attrs"
|
||||
@input="onInput"
|
||||
@focus="focused"
|
||||
@@ -55,6 +56,11 @@
|
||||
class="dropdown-item is-disabled">
|
||||
<slot name="empty"/>
|
||||
</div>
|
||||
<div
|
||||
v-if="hasFooterSlot"
|
||||
class="dropdown-item">
|
||||
<slot name="footer"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
@@ -140,6 +146,13 @@
|
||||
*/
|
||||
hasHeaderSlot() {
|
||||
return !!this.$slots.header
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if exists "footer" slot
|
||||
*/
|
||||
hasFooterSlot() {
|
||||
return !!this.$slots.footer
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
||||
+7
-1
@@ -2,6 +2,7 @@
|
||||
<component
|
||||
:is="tag"
|
||||
class="button"
|
||||
v-bind="$attrs"
|
||||
:type="nativeType"
|
||||
:class="[size, type, {
|
||||
'is-rounded': rounded,
|
||||
@@ -75,7 +76,12 @@
|
||||
return [
|
||||
'button',
|
||||
'a',
|
||||
'input'
|
||||
'input',
|
||||
'router-link',
|
||||
'nuxt-link',
|
||||
'n-link',
|
||||
'NuxtLink',
|
||||
'NLink'
|
||||
].indexOf(value) >= 0
|
||||
}
|
||||
}
|
||||
|
||||
+17
-15
@@ -11,7 +11,7 @@
|
||||
ref="input"
|
||||
slot="trigger"
|
||||
autocomplete="off"
|
||||
:value="formatValue(dateSelected)"
|
||||
:value="formatValue(computedValue)"
|
||||
:placeholder="placeholder"
|
||||
:size="size"
|
||||
:icon="icon"
|
||||
@@ -21,9 +21,12 @@
|
||||
:readonly="!editable"
|
||||
:rounded="rounded"
|
||||
v-bind="$attrs"
|
||||
@change.native="onChange($event.target.value)"
|
||||
@focus="$emit('focus', $event)"
|
||||
@blur="$emit('blur', $event) && checkHtml5Validity()"/>
|
||||
:use-html5-validation="useHtml5Validation"
|
||||
@click.native.stop="toggle(true)"
|
||||
@keyup.native.enter="toggle(true)"
|
||||
@change.native="onChangeNativePicker"
|
||||
@focus="handleOnFocus"
|
||||
@blur="onBlur() && checkHtml5Validity()"/>
|
||||
|
||||
<div
|
||||
class="card"
|
||||
@@ -83,7 +86,7 @@
|
||||
:min="minFaceValue"
|
||||
:max="maxFaceValue"
|
||||
:face-numbers="isSelectingHour ? hours : minutes"
|
||||
:disabled-values="faceDisabledValues()"
|
||||
:disabled-values="faceDisabledValues"
|
||||
:double="isSelectingHour && isHourFormat24"
|
||||
:value="isSelectingHour ? hoursSelected : minutesSelected"
|
||||
@input="onClockInput"
|
||||
@@ -102,7 +105,7 @@
|
||||
ref="input"
|
||||
type="time"
|
||||
autocomplete="off"
|
||||
:value="formatHHMMSS(value)"
|
||||
:value="formatHHMMSS(computedValue)"
|
||||
:placeholder="placeholder"
|
||||
:size="size"
|
||||
:icon="icon"
|
||||
@@ -113,16 +116,18 @@
|
||||
:disabled="disabled"
|
||||
:readonly="false"
|
||||
v-bind="$attrs"
|
||||
:use-html5-validation="useHtml5Validation"
|
||||
@click.native.stop="toggle(true)"
|
||||
@keyup.native.enter="toggle(true)"
|
||||
@change.native="onChangeNativePicker"
|
||||
@focus="$emit('focus', $event)"
|
||||
@blur="$emit('blur', $event) && checkHtml5Validity()"/>
|
||||
@focus="handleOnFocus"
|
||||
@blur="onBlur() && checkHtml5Validity()"/>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TimepickerMixin from '../../utils/TimepickerMixin'
|
||||
|
||||
import Dropdown from '../dropdown/Dropdown'
|
||||
import DropdownItem from '../dropdown/DropdownItem'
|
||||
import Input from '../input/Input'
|
||||
@@ -205,6 +210,9 @@
|
||||
},
|
||||
faceSize() {
|
||||
return this.pickerSize - (outerPadding * 2)
|
||||
},
|
||||
faceDisabledValues() {
|
||||
return this.isSelectingHour ? this.isHourDisabled : this.isMinuteDisabled
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -227,13 +235,7 @@
|
||||
this.meridienSelected = value
|
||||
this.onMeridienChange(value)
|
||||
}
|
||||
},
|
||||
faceDisabledValues() {
|
||||
return this.isSelectingHour ? this.isHourDisabled : this.isMinuteDisabled
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.incrementMinutes = 5
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
+2
-1
@@ -46,9 +46,10 @@ describe('BDatepicker', () => {
|
||||
expect($dropdown.isVisible()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('call toggle method', () => {
|
||||
it('call toggle method', async () => {
|
||||
wrapper.vm.$refs.dropdown.isActive = false
|
||||
wrapper.vm.toggle()
|
||||
await wrapper.vm.$nextTick()
|
||||
expect(wrapper.vm.$refs.dropdown.isActive).toBeTruthy()
|
||||
expect($dropdown.isVisible()).toBeTruthy()
|
||||
|
||||
|
||||
+196
-80
@@ -11,7 +11,7 @@
|
||||
ref="input"
|
||||
slot="trigger"
|
||||
autocomplete="off"
|
||||
:value="formatValue(dateSelected)"
|
||||
:value="formatValue(computedValue)"
|
||||
:placeholder="placeholder"
|
||||
:size="size"
|
||||
:icon="icon"
|
||||
@@ -21,8 +21,9 @@
|
||||
:disabled="disabled"
|
||||
:readonly="!editable"
|
||||
v-bind="$attrs"
|
||||
@click.native.stop="toggle(true)"
|
||||
@keyup.native.enter="toggle(true)"
|
||||
:use-html5-validation="useHtml5Validation"
|
||||
@click.native="onInputClick"
|
||||
@keyup.native.enter="togglePicker(true)"
|
||||
@change.native="onChange($event.target.value)"
|
||||
@focus="handleOnFocus"
|
||||
@blur="onBlur" />
|
||||
@@ -37,14 +38,14 @@
|
||||
class="pagination field is-centered"
|
||||
:class="size">
|
||||
<a
|
||||
v-show="!isFirstMonth && !disabled"
|
||||
v-show="!showPrev && !disabled"
|
||||
class="pagination-previous"
|
||||
role="button"
|
||||
href="#"
|
||||
:disabled="disabled"
|
||||
@click.prevent="decrementMonth"
|
||||
@keydown.enter.prevent="decrementMonth"
|
||||
@keydown.space.prevent="decrementMonth">
|
||||
@click.prevent="prev"
|
||||
@keydown.enter.prevent="prev"
|
||||
@keydown.space.prevent="prev">
|
||||
|
||||
<b-icon
|
||||
icon="chevron-left"
|
||||
@@ -53,14 +54,14 @@
|
||||
type="is-primary is-clickable"/>
|
||||
</a>
|
||||
<a
|
||||
v-show="!isLastMonth && !disabled"
|
||||
v-show="!showNext && !disabled"
|
||||
class="pagination-next"
|
||||
role="button"
|
||||
href="#"
|
||||
:disabled="disabled"
|
||||
@click.prevent="incrementMonth"
|
||||
@keydown.enter.prevent="incrementMonth"
|
||||
@keydown.space.prevent="incrementMonth">
|
||||
@click.prevent="next"
|
||||
@keydown.enter.prevent="next"
|
||||
@keydown.space.prevent="next">
|
||||
|
||||
<b-icon
|
||||
icon="chevron-right"
|
||||
@@ -71,6 +72,7 @@
|
||||
<div class="pagination-list">
|
||||
<b-field>
|
||||
<b-select
|
||||
v-if="!isTypeMonth"
|
||||
v-model="focusedDateData.month"
|
||||
:disabled="disabled"
|
||||
:size="size">
|
||||
@@ -97,9 +99,11 @@
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="datepicker-content">
|
||||
<div
|
||||
v-if="!isTypeMonth"
|
||||
class="datepicker-content">
|
||||
<b-datepicker-table
|
||||
v-model="dateSelected"
|
||||
v-model="computedValue"
|
||||
:day-names="dayNames"
|
||||
:month-names="monthNames"
|
||||
:first-day-of-week="firstDayOfWeek"
|
||||
@@ -113,7 +117,26 @@
|
||||
:events="events"
|
||||
:indicators="indicators"
|
||||
:date-creator="dateCreator"
|
||||
@close="toggle(false)"/>
|
||||
:type-month="isTypeMonth"
|
||||
:nearby-month-days="nearbyMonthDays"
|
||||
:nearby-selectable-month-days="nearbySelectableMonthDays"
|
||||
@close="togglePicker(false)"/>
|
||||
</div>
|
||||
<div v-else>
|
||||
<b-datepicker-month
|
||||
v-model="computedValue"
|
||||
:month-names="monthNames"
|
||||
:min-date="minDate"
|
||||
:max-date="maxDate"
|
||||
:focused="focusedDateData"
|
||||
:disabled="disabled"
|
||||
:unselectable-dates="unselectableDates"
|
||||
:unselectable-days-of-week="unselectableDaysOfWeek"
|
||||
:selectable-dates="selectableDates"
|
||||
:events="events"
|
||||
:indicators="indicators"
|
||||
:date-creator="dateCreator"
|
||||
@close="togglePicker(false)"/>
|
||||
</div>
|
||||
|
||||
<footer
|
||||
@@ -127,22 +150,21 @@
|
||||
<b-input
|
||||
v-else
|
||||
ref="input"
|
||||
type="date"
|
||||
:type="!isTypeMonth ? 'date' : 'month'"
|
||||
autocomplete="off"
|
||||
:value="formatYYYYMMDD(value)"
|
||||
:value="formatNative(computedValue)"
|
||||
:placeholder="placeholder"
|
||||
:size="size"
|
||||
:icon="icon"
|
||||
:icon-pack="iconPack"
|
||||
:loading="loading"
|
||||
:max="formatYYYYMMDD(maxDate)"
|
||||
:min="formatYYYYMMDD(minDate)"
|
||||
:max="formatNative(maxDate)"
|
||||
:min="formatNative(minDate)"
|
||||
:disabled="disabled"
|
||||
:readonly="false"
|
||||
v-bind="$attrs"
|
||||
:use-html5-validation="useHtml5Validation"
|
||||
@change.native="onChangeNativePicker"
|
||||
@click.native.stop="toggle(true)"
|
||||
@keyup.native.enter="toggle(true)"
|
||||
@focus="handleOnFocus"
|
||||
@blur="onBlur"/>
|
||||
</div>
|
||||
@@ -159,12 +181,37 @@
|
||||
import Field from '../field/Field'
|
||||
import Select from '../select/Select'
|
||||
import Icon from '../icon/Icon'
|
||||
|
||||
import DatepickerTable from './DatepickerTable'
|
||||
import DatepickerMonth from './DatepickerMonth'
|
||||
|
||||
const defaultDateFormatter = (date, vm) => {
|
||||
const yyyyMMdd = date.getFullYear() +
|
||||
'/' + (date.getMonth() + 1) +
|
||||
'/' + date.getDate()
|
||||
const d = new Date(yyyyMMdd)
|
||||
return !vm.isTypeMonth ? d.toLocaleDateString()
|
||||
: d.toLocaleDateString(undefined, { year: 'numeric', month: '2-digit' })
|
||||
}
|
||||
|
||||
const defaultDateParser = (date, vm) => {
|
||||
if (!vm.isTypeMonth) return new Date(Date.parse(date))
|
||||
if (date) {
|
||||
const s = date.split('/')
|
||||
const year = s[0].length === 4 ? s[0] : s[1]
|
||||
const month = s[0].length === 2 ? s[0] : s[1]
|
||||
if (year && month) {
|
||||
return new Date(parseInt(year, 10), parseInt(month - 1, 10), 1, 0, 0, 0, 0)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'BDatepicker',
|
||||
components: {
|
||||
[DatepickerTable.name]: DatepickerTable,
|
||||
[DatepickerMonth.name]: DatepickerMonth,
|
||||
[Input.name]: Input,
|
||||
[Field.name]: Field,
|
||||
[Select.name]: Select,
|
||||
@@ -242,25 +289,21 @@
|
||||
selectableDates: Array,
|
||||
dateFormatter: {
|
||||
type: Function,
|
||||
default: (date) => {
|
||||
default: (date, vm) => {
|
||||
if (typeof config.defaultDateFormatter === 'function') {
|
||||
return config.defaultDateFormatter(date)
|
||||
} else {
|
||||
const yyyyMMdd = date.getFullYear() +
|
||||
'/' + (date.getMonth() + 1) +
|
||||
'/' + date.getDate()
|
||||
const d = new Date(yyyyMMdd)
|
||||
return d.toLocaleDateString()
|
||||
return defaultDateFormatter(date, vm)
|
||||
}
|
||||
}
|
||||
},
|
||||
dateParser: {
|
||||
type: Function,
|
||||
default: (date) => {
|
||||
default: (date, vm) => {
|
||||
if (typeof config.defaultDateParser === 'function') {
|
||||
return config.defaultDateParser(date)
|
||||
} else {
|
||||
return new Date(Date.parse(date))
|
||||
return defaultDateParser(date, vm)
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -286,7 +329,29 @@
|
||||
type: String,
|
||||
default: 'dots'
|
||||
},
|
||||
openOnFocus: Boolean
|
||||
openOnFocus: Boolean,
|
||||
yearsRange: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return config.defaultDatepickerYearsRange
|
||||
}
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
validator: (value) => {
|
||||
return [
|
||||
'month'
|
||||
].indexOf(value) >= 0
|
||||
}
|
||||
},
|
||||
nearbyMonthDays: {
|
||||
type: Boolean,
|
||||
default: () => config.defaultDatepickerNearbyMonthDays
|
||||
},
|
||||
nearbySelectableMonthDays: {
|
||||
type: Boolean,
|
||||
default: () => config.defaultDatepickerNearbySelectableMonthDays
|
||||
}
|
||||
},
|
||||
data() {
|
||||
const focusedDate = this.value || this.focusedDate || this.dateCreator()
|
||||
@@ -302,17 +367,27 @@
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
computedValue: {
|
||||
get() {
|
||||
return this.dateSelected
|
||||
},
|
||||
set(value) {
|
||||
this.updateInternalState(value)
|
||||
this.togglePicker(false)
|
||||
this.$emit('input', value)
|
||||
}
|
||||
},
|
||||
/*
|
||||
* Returns an array of years for the year dropdown. If earliest/latest
|
||||
* dates are set by props, range of years will fall within those dates.
|
||||
*/
|
||||
listOfYears() {
|
||||
let latestYear = this.focusedDateData.year + 3
|
||||
let latestYear = this.focusedDateData.year + this.yearsRange[1]
|
||||
if (this.maxDate && this.maxDate.getFullYear() < latestYear) {
|
||||
latestYear = this.maxDate.getFullYear()
|
||||
}
|
||||
|
||||
let earliestYear = (latestYear - 100) + 3
|
||||
let earliestYear = this.focusedDateData.year + this.yearsRange[0]
|
||||
if (this.minDate && this.minDate.getFullYear() > earliestYear) {
|
||||
earliestYear = this.minDate.getFullYear()
|
||||
}
|
||||
@@ -325,15 +400,21 @@
|
||||
return arrayOfYears.reverse()
|
||||
},
|
||||
|
||||
isFirstMonth() {
|
||||
showPrev() {
|
||||
if (!this.minDate) return false
|
||||
if (this.isTypeMonth) {
|
||||
return this.focusedDateData.year <= this.minDate.getFullYear()
|
||||
}
|
||||
const dateToCheck = new Date(this.focusedDateData.year, this.focusedDateData.month)
|
||||
const date = new Date(this.minDate.getFullYear(), this.minDate.getMonth())
|
||||
return (dateToCheck <= date)
|
||||
},
|
||||
|
||||
isLastMonth() {
|
||||
showNext() {
|
||||
if (!this.maxDate) return false
|
||||
if (this.isTypeMonth) {
|
||||
return this.focusedDateData.year >= this.maxDate.getFullYear()
|
||||
}
|
||||
const dateToCheck = new Date(this.focusedDateData.year, this.focusedDateData.month)
|
||||
const date = new Date(this.maxDate.getFullYear(), this.maxDate.getMonth())
|
||||
return (dateToCheck >= date)
|
||||
@@ -341,31 +422,21 @@
|
||||
|
||||
isMobile() {
|
||||
return this.mobileNative && isMobile.any()
|
||||
},
|
||||
|
||||
isTypeMonth() {
|
||||
return this.type === 'month'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
/*
|
||||
* Emit input event with selected date as payload, set isActive to false.
|
||||
* Update internal focusedDateData
|
||||
*/
|
||||
dateSelected(value) {
|
||||
const currentDate = !value ? this.dateCreator() : value
|
||||
this.focusedDateData = {
|
||||
month: currentDate.getMonth(),
|
||||
year: currentDate.getFullYear()
|
||||
}
|
||||
this.$emit('input', value)
|
||||
this.toggle()
|
||||
},
|
||||
|
||||
/**
|
||||
* When v-model is changed:
|
||||
* 1. Update internal value.
|
||||
* 2. If it's invalid, validate again.
|
||||
*/
|
||||
value(value) {
|
||||
this.dateSelected = value
|
||||
|
||||
this.updateInternalState(value)
|
||||
this.togglePicker(false)
|
||||
!this.isValid && this.$refs.input.checkHtml5Validity()
|
||||
},
|
||||
|
||||
@@ -389,24 +460,17 @@
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/*
|
||||
* Emit input event with selected date as payload for v-model in parent
|
||||
*/
|
||||
updateSelectedDate(date) {
|
||||
this.dateSelected = date
|
||||
},
|
||||
|
||||
/*
|
||||
* Parse string into date
|
||||
*/
|
||||
onChange(value) {
|
||||
const date = this.dateParser(value)
|
||||
const date = this.dateParser(value, this)
|
||||
if (date && !isNaN(date)) {
|
||||
this.dateSelected = date
|
||||
this.computedValue = date
|
||||
} else {
|
||||
// Force refresh input value when not valid date
|
||||
this.dateSelected = null
|
||||
this.$refs.input.newValue = this.dateSelected
|
||||
this.computedValue = null
|
||||
this.$refs.input.newValue = this.computedValue
|
||||
}
|
||||
},
|
||||
|
||||
@@ -415,7 +479,7 @@
|
||||
*/
|
||||
formatValue(value) {
|
||||
if (value && !isNaN(value)) {
|
||||
return this.dateFormatter(value)
|
||||
return this.dateFormatter(value, this)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
@@ -423,34 +487,47 @@
|
||||
|
||||
/*
|
||||
* Either decrement month by 1 if not January or decrement year by 1
|
||||
* and set month to 11 (December)
|
||||
* and set month to 11 (December) or decrement year when 'month'
|
||||
*/
|
||||
decrementMonth() {
|
||||
prev() {
|
||||
if (this.disabled) return
|
||||
|
||||
if (this.focusedDateData.month > 0) {
|
||||
this.focusedDateData.month -= 1
|
||||
} else {
|
||||
this.focusedDateData.month = 11
|
||||
if (this.isTypeMonth) {
|
||||
this.focusedDateData.year -= 1
|
||||
} else {
|
||||
if (this.focusedDateData.month > 0) {
|
||||
this.focusedDateData.month -= 1
|
||||
} else {
|
||||
this.focusedDateData.month = 11
|
||||
this.focusedDateData.year -= 1
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Either increment month by 1 if not December or increment year by 1
|
||||
* and set month to 0 (January)
|
||||
* and set month to 0 (January) or increment year when 'month'
|
||||
*/
|
||||
incrementMonth() {
|
||||
next() {
|
||||
if (this.disabled) return
|
||||
|
||||
if (this.focusedDateData.month < 11) {
|
||||
this.focusedDateData.month += 1
|
||||
} else {
|
||||
this.focusedDateData.month = 0
|
||||
if (this.isTypeMonth) {
|
||||
this.focusedDateData.year += 1
|
||||
} else {
|
||||
if (this.focusedDateData.month < 11) {
|
||||
this.focusedDateData.month += 1
|
||||
} else {
|
||||
this.focusedDateData.month = 0
|
||||
this.focusedDateData.year += 1
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
formatNative(value) {
|
||||
return this.isTypeMonth
|
||||
? this.formatYYYYMM(value) : this.formatYYYYMMDD(value)
|
||||
},
|
||||
|
||||
/*
|
||||
* Format date into string 'YYYY-MM-DD'
|
||||
*/
|
||||
@@ -467,18 +544,41 @@
|
||||
return ''
|
||||
},
|
||||
|
||||
/*
|
||||
* Format date into string 'YYYY-MM'
|
||||
*/
|
||||
formatYYYYMM(value) {
|
||||
const date = new Date(value)
|
||||
if (value && !isNaN(date)) {
|
||||
const year = date.getFullYear()
|
||||
const month = date.getMonth() + 1
|
||||
return year + '-' +
|
||||
((month < 10 ? '0' : '') + month)
|
||||
}
|
||||
return ''
|
||||
},
|
||||
|
||||
/*
|
||||
* Parse date from string
|
||||
*/
|
||||
onChangeNativePicker(event) {
|
||||
const date = event.target.value
|
||||
this.dateSelected = date ? new Date(date.replace(/-/g, '/')) : null
|
||||
this.computedValue = date ? new Date(date.replace(/-/g, '/')) : null
|
||||
},
|
||||
|
||||
updateInternalState(value) {
|
||||
const currentDate = !value ? this.dateCreator() : value
|
||||
this.focusedDateData = {
|
||||
month: currentDate.getMonth(),
|
||||
year: currentDate.getFullYear()
|
||||
}
|
||||
this.dateSelected = value
|
||||
},
|
||||
|
||||
/*
|
||||
* Toggle datepicker
|
||||
*/
|
||||
toggle(active) {
|
||||
togglePicker(active) {
|
||||
if (this.$refs.dropdown) {
|
||||
this.$refs.dropdown.isActive = typeof active === 'boolean'
|
||||
? active
|
||||
@@ -489,10 +589,26 @@
|
||||
/*
|
||||
* Call default onFocus method and show datepicker
|
||||
*/
|
||||
handleOnFocus() {
|
||||
this.onFocus()
|
||||
handleOnFocus(event) {
|
||||
this.onFocus(event)
|
||||
if (this.openOnFocus) {
|
||||
this.toggle(true)
|
||||
this.togglePicker(true)
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Toggle dropdown
|
||||
*/
|
||||
toggle() {
|
||||
this.$refs.dropdown.toggle()
|
||||
},
|
||||
|
||||
/*
|
||||
* Avoid dropdown toggle when is already visible
|
||||
*/
|
||||
onInputClick(event) {
|
||||
if (this.$refs.dropdown.isActive) {
|
||||
event.stopPropagation()
|
||||
}
|
||||
},
|
||||
|
||||
@@ -501,8 +617,8 @@
|
||||
*/
|
||||
keyPress(event) {
|
||||
// Esc key
|
||||
if (this.$refs.dropdown.isActive && event.keyCode === 27) {
|
||||
this.toggle(false)
|
||||
if (this.$refs.dropdown && this.$refs.dropdown.isActive && event.keyCode === 27) {
|
||||
this.togglePicker(false)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
import { shallowMount } from '@vue/test-utils'
|
||||
import BDatepickerMonth from '@components/datepicker/DatepickerMonth'
|
||||
|
||||
import config, {setOptions} from '@utils/config'
|
||||
|
||||
describe('BDatepickerMonth', () => {
|
||||
beforeEach(() => {
|
||||
setOptions(Object.assign(config, {
|
||||
defaultMonthNames: [
|
||||
'January', 'February', 'March', 'April', 'May', 'June', 'July',
|
||||
'August', 'September', 'October', 'November', 'December'
|
||||
],
|
||||
focusedDate: new Date('2018-07')
|
||||
}))
|
||||
})
|
||||
|
||||
const dateCreator = () => new Date()
|
||||
|
||||
it('is called', () => {
|
||||
const wrapper = shallowMount(BDatepickerMonth, {
|
||||
propsData: {
|
||||
monthNames: config.defaultMonthNames,
|
||||
focused: {
|
||||
month: config.focusedDate.getMonth(),
|
||||
year: config.focusedDate.getFullYear()
|
||||
},
|
||||
dateCreator
|
||||
}
|
||||
})
|
||||
expect(wrapper.name()).toBe('BDatepickerMonth')
|
||||
expect(wrapper.isVueInstance()).toBeTruthy()
|
||||
})
|
||||
})
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
<template>
|
||||
<section class="datepicker-table">
|
||||
<div class="datepicker-body" :class="{'has-events':hasEvents}">
|
||||
<div class="datepicker-months">
|
||||
<template v-for="(date, index) in monthDates">
|
||||
<a
|
||||
v-if="selectableDate(date) && !disabled"
|
||||
:key="index"
|
||||
:class="[
|
||||
classObject(date),
|
||||
{'has-event': eventsDateMatch(date)},
|
||||
indicators
|
||||
]"
|
||||
class="datepicker-cell"
|
||||
role="button"
|
||||
href="#"
|
||||
:disabled="disabled"
|
||||
@click.prevent="emitChosenDate(date)"
|
||||
@keydown.enter.prevent="emitChosenDate(date)"
|
||||
@keydown.space.prevent="emitChosenDate(date)">
|
||||
{{ monthNames[date.getMonth()] }}
|
||||
<div class="events" v-if="eventsDateMatch(date)">
|
||||
<div
|
||||
class="event"
|
||||
:class="event.type"
|
||||
v-for="(event, index) in eventsDateMatch(date)"
|
||||
:key="index"/>
|
||||
</div>
|
||||
</a>
|
||||
<div
|
||||
v-else
|
||||
:key="index"
|
||||
:class="classObject(date)"
|
||||
class="datepicker-cell">
|
||||
{{ monthNames[date.getMonth()] }}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'BDatepickerMonth',
|
||||
props: {
|
||||
value: Date,
|
||||
monthNames: Array,
|
||||
events: Array,
|
||||
indicators: String,
|
||||
minDate: Date,
|
||||
maxDate: Date,
|
||||
focused: Object,
|
||||
disabled: Boolean,
|
||||
dateCreator: Function,
|
||||
unselectableDates: Array,
|
||||
unselectableDaysOfWeek: Array,
|
||||
selectableDates: Array
|
||||
},
|
||||
computed: {
|
||||
hasEvents() {
|
||||
return this.events && this.events.length
|
||||
},
|
||||
|
||||
/*
|
||||
* Return array of all events in the specified month
|
||||
*/
|
||||
eventsInThisYear() {
|
||||
if (!this.events) return []
|
||||
|
||||
const yearEvents = []
|
||||
|
||||
for (let i = 0; i < this.events.length; i++) {
|
||||
let event = this.events[i]
|
||||
|
||||
if (!event.hasOwnProperty('date')) {
|
||||
event = { date: event }
|
||||
}
|
||||
if (!event.hasOwnProperty('type')) {
|
||||
event.type = 'is-primary'
|
||||
}
|
||||
if (
|
||||
event.date.getFullYear() === this.focused.year
|
||||
) {
|
||||
yearEvents.push(event)
|
||||
}
|
||||
}
|
||||
|
||||
return yearEvents
|
||||
},
|
||||
monthDates() {
|
||||
const year = this.focused.year
|
||||
const months = []
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const d = new Date(year, i, 1)
|
||||
d.setHours(0, 0, 0, 0)
|
||||
months.push(d)
|
||||
}
|
||||
return months
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
selectableDate(day) {
|
||||
const validity = []
|
||||
|
||||
if (this.minDate) {
|
||||
validity.push(day >= this.minDate)
|
||||
}
|
||||
|
||||
if (this.maxDate) {
|
||||
validity.push(day <= this.maxDate)
|
||||
}
|
||||
|
||||
validity.push(day.getFullYear() === this.focused.year)
|
||||
|
||||
if (this.selectableDates) {
|
||||
for (let i = 0; i < this.selectableDates.length; i++) {
|
||||
const enabledDate = this.selectableDates[i]
|
||||
if (day.getFullYear() === enabledDate.getFullYear() &&
|
||||
day.getMonth() === enabledDate.getMonth()) {
|
||||
return true
|
||||
} else {
|
||||
validity.push(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.unselectableDates) {
|
||||
for (let i = 0; i < this.unselectableDates.length; i++) {
|
||||
const disabledDate = this.unselectableDates[i]
|
||||
validity.push(
|
||||
day.getFullYear() !== disabledDate.getFullYear() ||
|
||||
day.getMonth() !== disabledDate.getMonth()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (this.unselectableDaysOfWeek) {
|
||||
for (let i = 0; i < this.unselectableDaysOfWeek.length; i++) {
|
||||
const dayOfWeek = this.unselectableDaysOfWeek[i]
|
||||
validity.push(day.getDay() !== dayOfWeek)
|
||||
}
|
||||
}
|
||||
|
||||
return validity.indexOf(false) < 0
|
||||
},
|
||||
eventsDateMatch(day) {
|
||||
if (!this.eventsInThisYear.length) return false
|
||||
|
||||
const monthEvents = []
|
||||
|
||||
for (let i = 0; i < this.eventsInThisYear.length; i++) {
|
||||
if (this.eventsInThisYear[i].date.getMonth() === day.getMonth()) {
|
||||
monthEvents.push(this.events[i])
|
||||
}
|
||||
}
|
||||
|
||||
if (!monthEvents.length) {
|
||||
return false
|
||||
}
|
||||
|
||||
return monthEvents
|
||||
},
|
||||
/*
|
||||
* Build classObject for cell using validations
|
||||
*/
|
||||
classObject(day) {
|
||||
function dateMatch(dateOne, dateTwo) {
|
||||
// if either date is null or undefined, return false
|
||||
if (!dateOne || !dateTwo) {
|
||||
return false
|
||||
}
|
||||
|
||||
return (dateOne.getFullYear() === dateTwo.getFullYear() &&
|
||||
dateOne.getMonth() === dateTwo.getMonth())
|
||||
}
|
||||
|
||||
return {
|
||||
'is-selected': dateMatch(day, this.value),
|
||||
'is-today': dateMatch(day, this.dateCreator()),
|
||||
'is-selectable': this.selectableDate(day) && !this.disabled,
|
||||
'is-unselectable': !this.selectableDate(day) || this.disabled
|
||||
}
|
||||
},
|
||||
/*
|
||||
* Emit select event with chosen date as payload
|
||||
*/
|
||||
emitChosenDate(day) {
|
||||
if (this.disabled) return
|
||||
|
||||
if (this.selectableDate(day)) {
|
||||
this.$emit('input', day)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
+5
-1
@@ -24,6 +24,8 @@
|
||||
:events="eventsInThisWeek(week)"
|
||||
:indicators="indicators"
|
||||
:date-creator="dateCreator"
|
||||
:nearby-month-days="nearbyMonthDays"
|
||||
:nearby-selectable-month-days="nearbySelectableMonthDays"
|
||||
@select="updateSelectedDate"/>
|
||||
</div>
|
||||
</section>
|
||||
@@ -51,7 +53,9 @@
|
||||
dateCreator: Function,
|
||||
unselectableDates: Array,
|
||||
unselectableDaysOfWeek: Array,
|
||||
selectableDates: Array
|
||||
selectableDates: Array,
|
||||
nearbyMonthDays: Boolean,
|
||||
nearbySelectableMonthDays: Boolean
|
||||
},
|
||||
computed: {
|
||||
visibleDayNames() {
|
||||
|
||||
+11
-7
@@ -4,7 +4,7 @@
|
||||
<a
|
||||
v-if="selectableDate(day) && !disabled"
|
||||
:key="index"
|
||||
:class="[classObject(day), {'has-event':eventsDateMatch(day)}, indicators]"
|
||||
:class="[classObject(day), {'has-event': eventsDateMatch(day)}, indicators]"
|
||||
class="datepicker-cell"
|
||||
role="button"
|
||||
href="#"
|
||||
@@ -13,7 +13,6 @@
|
||||
@keydown.enter.prevent="emitChosenDate(day)"
|
||||
@keydown.space.prevent="emitChosenDate(day)">
|
||||
{{ day.getDate() }}
|
||||
|
||||
<div class="events" v-if="eventsDateMatch(day)">
|
||||
<div
|
||||
class="event"
|
||||
@@ -21,7 +20,6 @@
|
||||
v-for="(event, index) in eventsDateMatch(day)"
|
||||
:key="index"/>
|
||||
</div>
|
||||
|
||||
</a>
|
||||
<div
|
||||
v-else
|
||||
@@ -55,7 +53,9 @@
|
||||
selectableDates: Array,
|
||||
events: Array,
|
||||
indicators: String,
|
||||
dateCreator: Function
|
||||
dateCreator: Function,
|
||||
nearbyMonthDays: Boolean,
|
||||
nearbySelectableMonthDays: Boolean
|
||||
},
|
||||
methods: {
|
||||
/*
|
||||
@@ -73,7 +73,9 @@
|
||||
validity.push(day <= this.maxDate)
|
||||
}
|
||||
|
||||
validity.push(day.getMonth() === this.month)
|
||||
if (this.nearbyMonthDays && !this.nearbySelectableMonthDays) {
|
||||
validity.push(day.getMonth() === this.month)
|
||||
}
|
||||
|
||||
if (this.selectableDates) {
|
||||
for (let i = 0; i < this.selectableDates.length; i++) {
|
||||
@@ -121,7 +123,7 @@
|
||||
},
|
||||
|
||||
eventsDateMatch(day) {
|
||||
if (!this.events.length) return false
|
||||
if (!this.events || !this.events.length) return false
|
||||
|
||||
const dayEvents = []
|
||||
|
||||
@@ -157,7 +159,9 @@
|
||||
'is-selected': dateMatch(day, this.selectedDate),
|
||||
'is-today': dateMatch(day, this.dateCreator()),
|
||||
'is-selectable': this.selectableDate(day) && !this.disabled,
|
||||
'is-unselectable': !this.selectableDate(day) || this.disabled
|
||||
'is-unselectable': !this.selectableDate(day) || this.disabled,
|
||||
'is-invisible': !this.nearbyMonthDays && day.getMonth() !== this.month,
|
||||
'is-nearby': this.nearbySelectableMonthDays && day.getMonth() !== this.month
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+44
-8
@@ -20,7 +20,7 @@
|
||||
</transition>
|
||||
<transition :name="animation">
|
||||
<div
|
||||
v-show="(!disabled && (isActive || hoverable)) || inline"
|
||||
v-show="(!disabled && (isActive || isHoverable)) || inline"
|
||||
ref="dropdownMenu"
|
||||
class="dropdown-menu"
|
||||
:aria-hidden="!isActive">
|
||||
@@ -35,6 +35,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import config from '../../utils/config'
|
||||
|
||||
export default {
|
||||
name: 'BDropdown',
|
||||
props: {
|
||||
@@ -57,7 +59,9 @@
|
||||
},
|
||||
mobileModal: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
default: () => {
|
||||
return config.defaultDropdownMobileModal
|
||||
}
|
||||
},
|
||||
ariaRole: {
|
||||
type: String,
|
||||
@@ -66,12 +70,18 @@
|
||||
animation: {
|
||||
type: String,
|
||||
default: 'fade'
|
||||
},
|
||||
multiple: Boolean,
|
||||
closeOnClick: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selected: this.value,
|
||||
isActive: false,
|
||||
isHoverable: this.hoverable,
|
||||
_isDropdown: true // Used internally by DropdownItem
|
||||
}
|
||||
},
|
||||
@@ -115,12 +125,38 @@
|
||||
* 3. Close the dropdown.
|
||||
*/
|
||||
selectItem(value) {
|
||||
if (this.selected !== value) {
|
||||
this.$emit('change', value)
|
||||
this.selected = value
|
||||
if (this.multiple) {
|
||||
if (this.selected) {
|
||||
const index = this.selected.indexOf(value)
|
||||
if (index === -1) {
|
||||
this.selected.push(value)
|
||||
} else {
|
||||
this.selected.splice(index, 1)
|
||||
}
|
||||
} else {
|
||||
this.selected = [value]
|
||||
}
|
||||
this.$emit('change', this.selected)
|
||||
} else {
|
||||
if (this.selected !== value) {
|
||||
this.selected = value
|
||||
this.$emit('change', this.selected)
|
||||
}
|
||||
}
|
||||
this.$emit('input', this.selected)
|
||||
if (!this.multiple) {
|
||||
this.isActive = !this.closeOnClick
|
||||
/*
|
||||
* breaking change
|
||||
if (this.hoverable && this.closeOnClick) {
|
||||
this.isHoverable = false
|
||||
// Timeout for the animation complete before destroying
|
||||
setTimeout(() => {
|
||||
this.isHoverable = true
|
||||
}, 250)
|
||||
}
|
||||
*/
|
||||
}
|
||||
this.$emit('input', value)
|
||||
this.isActive = false
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -164,7 +200,7 @@
|
||||
* Toggle dropdown if it's not disabled.
|
||||
*/
|
||||
toggle() {
|
||||
if (this.disabled || this.hoverable) return
|
||||
if (this.disabled) return
|
||||
|
||||
if (!this.isActive) {
|
||||
// if not active, toggle after clickOutside event
|
||||
|
||||
+7
-2
@@ -42,7 +42,7 @@
|
||||
return {
|
||||
'is-disabled': this.$parent.disabled || this.disabled,
|
||||
'is-paddingless': this.paddingless,
|
||||
'is-active': this.value !== null && this.value === this.$parent.selected
|
||||
'is-active': this.isActive
|
||||
}
|
||||
},
|
||||
itemClasses() {
|
||||
@@ -50,7 +50,7 @@
|
||||
'dropdown-item': !this.hasLink,
|
||||
'is-disabled': this.disabled,
|
||||
'is-paddingless': this.paddingless,
|
||||
'is-active': this.value !== null && this.value === this.$parent.selected,
|
||||
'is-active': this.isActive,
|
||||
'has-link': this.hasLink
|
||||
}
|
||||
},
|
||||
@@ -62,6 +62,11 @@
|
||||
*/
|
||||
isClickable() {
|
||||
return !this.$parent.disabled && !this.separator && !this.disabled && !this.custom
|
||||
},
|
||||
isActive() {
|
||||
if (this.$parent.selected === null) return false
|
||||
if (this.$parent.multiple) return this.$parent.selected.indexOf(this.value) >= 0
|
||||
return this.value === this.$parent.selected
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
+20
-6
@@ -5,20 +5,22 @@
|
||||
class="field-label"
|
||||
:class="[customClass, fieldLabelSize]">
|
||||
<label
|
||||
v-if="label"
|
||||
v-if="hasLabel"
|
||||
:for="labelFor"
|
||||
:class="customClass"
|
||||
class="label" >
|
||||
{{ label }}
|
||||
<slot v-if="$slots.label" name="label"/>
|
||||
<template v-else>{{ label }}</template>
|
||||
</label>
|
||||
</div>
|
||||
<template v-else>
|
||||
<label
|
||||
v-if="label"
|
||||
v-if="hasLabel"
|
||||
:for="labelFor"
|
||||
:class="customClass"
|
||||
class="label">
|
||||
{{ label }}
|
||||
<slot v-if="$slots.label" name="label"/>
|
||||
<template v-else>{{ label }}</template>
|
||||
</label>
|
||||
</template>
|
||||
<b-field-body
|
||||
@@ -40,6 +42,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import config from '../../utils/config'
|
||||
import FieldBody from './FieldBody'
|
||||
|
||||
export default {
|
||||
@@ -61,7 +64,11 @@
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
customClass: String
|
||||
customClass: String,
|
||||
labelPosition: {
|
||||
type: String,
|
||||
default: () => { return config.defaultFieldLabelPosition }
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -76,7 +83,11 @@
|
||||
return [this.newPosition, {
|
||||
'is-expanded': this.expanded,
|
||||
'is-grouped-multiline': this.groupMultiline,
|
||||
'is-horizontal': this.horizontal
|
||||
'is-horizontal': this.horizontal,
|
||||
'is-floating-in-label': this.hasLabel && !this.horizontal &&
|
||||
this.labelPosition === 'inside',
|
||||
'is-floating-label': this.hasLabel && !this.horizontal &&
|
||||
this.labelPosition === 'on-border'
|
||||
}]
|
||||
},
|
||||
/**
|
||||
@@ -128,6 +139,9 @@
|
||||
}
|
||||
return messages.filter((m) => { if (m) return m }).join(' <br> ')
|
||||
}
|
||||
},
|
||||
hasLabel() {
|
||||
return this.label || this.$slots.label
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
||||
+3
-3
@@ -1,3 +1,3 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`BIcon render correctly 1`] = `<span class="icon"><i class="mdi mdi-undefined mdi-24px"></i></span>`;
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`BIcon render correctly 1`] = `<span class="icon"><i class="mdi mdi-undefined mdi-24px"></i></span>`;
|
||||
|
||||
+2
@@ -18,6 +18,7 @@ import Pagination from './pagination'
|
||||
import Radio from './radio'
|
||||
import Select from './select'
|
||||
import Snackbar from './snackbar'
|
||||
import Steps from './steps'
|
||||
import Switch from './switch'
|
||||
import Table from './table'
|
||||
import Tabs from './tabs'
|
||||
@@ -49,6 +50,7 @@ export {
|
||||
Radio,
|
||||
Select,
|
||||
Snackbar,
|
||||
Steps,
|
||||
Switch,
|
||||
Table,
|
||||
Tabs,
|
||||
|
||||
+14
-6
@@ -1,11 +1,14 @@
|
||||
<template>
|
||||
<transition :name="animation">
|
||||
<div v-if="isActive" class="modal is-active">
|
||||
<div
|
||||
v-if="isActive"
|
||||
class="modal is-active"
|
||||
:class="{ 'is-full-screen': fullScreen }">
|
||||
<div class="modal-background" @click="cancel('outside')"/>
|
||||
<div
|
||||
class="animation-content"
|
||||
:class="{ 'modal-content': !hasModalCard }"
|
||||
:style="{ maxWidth: newWidth }">
|
||||
:style="customStlye">
|
||||
<component
|
||||
v-if="component"
|
||||
v-bind="props"
|
||||
@@ -52,8 +55,6 @@
|
||||
type: [Array, Boolean],
|
||||
default: () => {
|
||||
return config.defaultModalCanCancel
|
||||
? config.defaultModalCanCancel
|
||||
: ['escape', 'x', 'outside', 'button']
|
||||
}
|
||||
},
|
||||
onCancel: {
|
||||
@@ -73,7 +74,8 @@
|
||||
'keep'
|
||||
].indexOf(value) >= 0
|
||||
}
|
||||
}
|
||||
},
|
||||
fullScreen: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -88,12 +90,18 @@
|
||||
cancelOptions() {
|
||||
return typeof this.canCancel === 'boolean'
|
||||
? this.canCancel
|
||||
? ['escape', 'x', 'outside', 'button']
|
||||
? config.defaultModalCanCancel
|
||||
: []
|
||||
: this.canCancel
|
||||
},
|
||||
showX() {
|
||||
return this.cancelOptions.indexOf('x') >= 0
|
||||
},
|
||||
customStlye() {
|
||||
if (!this.fullScreen) {
|
||||
return { maxWidth: this.newWidth }
|
||||
}
|
||||
return null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
||||
+4
-1
@@ -21,7 +21,10 @@
|
||||
aria-hidden/>
|
||||
</div>
|
||||
<div class="media-content">
|
||||
<p class="text" v-if="message">{{ message }}</p>
|
||||
<p
|
||||
class="text"
|
||||
v-if="message"
|
||||
v-html="message" />
|
||||
<slot v-else/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
newDuration: this.duration || config.detaultNotificationDuration
|
||||
newDuration: this.duration || config.defaultNotificationDuration
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+28
-29
@@ -1,17 +1,18 @@
|
||||
<template>
|
||||
<div class="b-numberinput field" :class="fieldClasses">
|
||||
<p class="control">
|
||||
<p
|
||||
class="control"
|
||||
@mouseup="onStopLongPress(false)"
|
||||
@mouseleave="onStopLongPress(false)"
|
||||
@touchend="onStopLongPress(false)"
|
||||
@touchcancel="onStopLongPress(false)">
|
||||
<button
|
||||
type="button"
|
||||
class="button"
|
||||
:class="buttonClasses"
|
||||
:disabled="disabled || disabledMin"
|
||||
@mousedown="onStartLongPress($event, false)"
|
||||
@mouseup="onStopLongPress(false)"
|
||||
@mouseleave="onStopLongPress(false)"
|
||||
@touchstart.prevent="onStartLongPress($event, false)"
|
||||
@touchend="onStopLongPress(false)"
|
||||
@touchcancel="onStopLongPress(false)"
|
||||
@click="onControlClick($event, false)">
|
||||
<b-icon
|
||||
icon="minus"
|
||||
@@ -22,6 +23,7 @@
|
||||
|
||||
<b-input
|
||||
type="number"
|
||||
ref="input"
|
||||
v-model.number="computedValue"
|
||||
v-bind="$attrs"
|
||||
:step="newStep"
|
||||
@@ -36,21 +38,23 @@
|
||||
:icon-pack="iconPack"
|
||||
:autocomplete="autocomplete"
|
||||
:expanded="expanded"
|
||||
:use-html5-validation="useHtml5Validation"
|
||||
@focus="$emit('focus', $event)"
|
||||
@blur="$emit('blur', $event)" />
|
||||
|
||||
<p class="control">
|
||||
<p
|
||||
class="control"
|
||||
@mouseup="onStopLongPress(true)"
|
||||
@mouseleave="onStopLongPress(true)"
|
||||
@touchend="onStopLongPress(true)"
|
||||
@touchcancel="onStopLongPress(true)">
|
||||
<button
|
||||
type="button"
|
||||
class="button"
|
||||
:class="buttonClasses"
|
||||
:disabled="disabled || disabledMax"
|
||||
@mousedown="onStartLongPress($event, true)"
|
||||
@mouseup="onStopLongPress(true)"
|
||||
@mouseleave="onStopLongPress(true)"
|
||||
@touchstart.prevent="onStartLongPress($event, true)"
|
||||
@touchend="onStopLongPress(true)"
|
||||
@touchcancel="onStopLongPress(true)"
|
||||
@click="onControlClick($event, true)">
|
||||
<b-icon
|
||||
icon="plus"
|
||||
@@ -96,7 +100,7 @@
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
newValue: this.value || parseFloat(this.min) || 0,
|
||||
newValue: !isNaN(this.value) ? this.value : parseFloat(this.min) || 0,
|
||||
newStep: this.step || 1,
|
||||
_elementRef: 'input'
|
||||
}
|
||||
@@ -107,9 +111,13 @@
|
||||
return this.newValue
|
||||
},
|
||||
set(value) {
|
||||
this.newValue = value
|
||||
this.$emit('input', value)
|
||||
!this.isValid && this.checkHtml5Validity()
|
||||
let newValue = value
|
||||
if (value === '') {
|
||||
newValue = parseFloat(this.min) || 0
|
||||
}
|
||||
this.newValue = newValue
|
||||
this.$emit('input', newValue)
|
||||
!this.isValid && this.$refs.input.checkHtml5Validity()
|
||||
}
|
||||
},
|
||||
fieldClasses() {
|
||||
@@ -177,7 +185,8 @@
|
||||
}
|
||||
},
|
||||
onControlClick(event, inc) {
|
||||
if (event.detail !== 0) return
|
||||
// IE 11 -> filter click event
|
||||
if (event.detail !== 0 || event.type === 'click') return
|
||||
if (inc) this.increment()
|
||||
else this.decrement()
|
||||
},
|
||||
@@ -185,30 +194,20 @@
|
||||
if (event.button !== 0 && event.type !== 'touchstart') return
|
||||
this._$intervalTime = new Date()
|
||||
clearInterval(this._$intervalRef)
|
||||
this._$intervalRef = this._$intervalRef = setInterval(() => {
|
||||
this._$intervalRef = setInterval(() => {
|
||||
if (inc) this.increment()
|
||||
else this.decrement()
|
||||
}, 100)
|
||||
}, 250)
|
||||
},
|
||||
onStopLongPress(inc) {
|
||||
if (!this._$intervalRef) return
|
||||
const d = new Date()
|
||||
if (d - this._$intervalTime < 100) {
|
||||
if (d - this._$intervalTime < 250) {
|
||||
if (inc) this.increment()
|
||||
else this.decrement()
|
||||
}
|
||||
clearInterval(this._$intervalRef)
|
||||
this._$intervalRef = null
|
||||
},
|
||||
onChange(event) {
|
||||
const value = event.target.value
|
||||
if (value) {
|
||||
const number = parseFloat(value)
|
||||
if (number < this.minNumber) {
|
||||
this.computedValue = this.minNumber
|
||||
} else if (number > this.maxNumber) {
|
||||
this.computedValue = this.maxNumber
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@
|
||||
icon="chevron-left"
|
||||
:pack="iconPack"
|
||||
both
|
||||
aria-hidden/>
|
||||
aria-hidden="true"/>
|
||||
</a>
|
||||
<a
|
||||
role="button"
|
||||
@@ -24,7 +24,7 @@
|
||||
icon="chevron-right"
|
||||
:pack="iconPack"
|
||||
both
|
||||
aria-hidden/>
|
||||
aria-hidden="true"/>
|
||||
</a>
|
||||
<ul class="pagination-list" v-if="!simple">
|
||||
<!--First-->
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
v-show="isActive"
|
||||
class="snackbar"
|
||||
:class="[type,position]">
|
||||
<p class="text">{{ message }}</p>
|
||||
<div class="text" v-html="message"/>
|
||||
<div
|
||||
v-if="actionText"
|
||||
class="action"
|
||||
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'BStepItem',
|
||||
props: {
|
||||
label: String,
|
||||
type: String | Object,
|
||||
icon: String,
|
||||
iconPack: String,
|
||||
clickable: Boolean,
|
||||
completed: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isActive: false,
|
||||
transitionName: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* Activate step, alter animation name based on the index.
|
||||
*/
|
||||
activate(oldIndex, index) {
|
||||
this.transitionName = index < oldIndex
|
||||
? 'slide-next'
|
||||
: 'slide-prev'
|
||||
this.isActive = true
|
||||
},
|
||||
|
||||
/**
|
||||
* Deactivate step, alter animation name based on the index.
|
||||
*/
|
||||
deactivate(oldIndex, index) {
|
||||
this.transitionName = index < oldIndex
|
||||
? 'slide-next'
|
||||
: 'slide-prev'
|
||||
this.isActive = false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (!this.$parent.$data._isSteps) {
|
||||
this.$destroy()
|
||||
throw new Error('You should wrap bStepItem on a bSteps')
|
||||
}
|
||||
this.$parent.stepItems.push(this)
|
||||
},
|
||||
beforeDestroy() {
|
||||
const index = this.$parent.stepItems.indexOf(this)
|
||||
if (index >= 0) {
|
||||
this.$parent.stepItems.splice(index, 1)
|
||||
}
|
||||
},
|
||||
render(createElement) {
|
||||
// if destroy apply v-if
|
||||
if (this.$parent.destroyOnHide) {
|
||||
if (!this.isActive || !this.visible) {
|
||||
return
|
||||
}
|
||||
}
|
||||
const vnode = createElement('div', {
|
||||
directives: [{
|
||||
name: 'show',
|
||||
value: this.isActive && this.visible
|
||||
}],
|
||||
attrs: { 'class': 'step-item' }
|
||||
}, this.$slots.default)
|
||||
// check animated prop
|
||||
if (this.$parent.animated) {
|
||||
return createElement('transition', {
|
||||
props: {
|
||||
'name': this.transitionName
|
||||
},
|
||||
on: {
|
||||
'before-enter': () => { this.$parent.isTransitioning = true },
|
||||
'after-enter': () => { this.$parent.isTransitioning = false }
|
||||
}
|
||||
}, [vnode])
|
||||
}
|
||||
return vnode
|
||||
}
|
||||
}
|
||||
</script>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import BSteps from '@components/steps/Steps'
|
||||
|
||||
describe('BSteps', () => {
|
||||
it('is called', () => {
|
||||
const wrapper = mount(BSteps)
|
||||
expect(wrapper.name()).toBe('BSteps')
|
||||
expect(wrapper.isVueInstance()).toBeTruthy()
|
||||
})
|
||||
})
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
<template>
|
||||
<div class="b-steps">
|
||||
<nav class="steps" :class="mainClasses">
|
||||
<ul class="step-items">
|
||||
<li
|
||||
v-for="(stepItem, index) in stepItems"
|
||||
:key="index"
|
||||
v-show="stepItem.visible"
|
||||
class="step-item"
|
||||
:class="[stepItem.type || type, {
|
||||
'is-active': activeStep === index,
|
||||
'is-completed': stepItem.completed || activeStep > index
|
||||
}]">
|
||||
<a
|
||||
class="step-link"
|
||||
:class="{'is-clickable': isItemClickable(stepItem)}"
|
||||
@click="stepItem.clickable && stepClick(index)">
|
||||
<div class="step-marker">
|
||||
<b-icon
|
||||
v-if="stepItem.icon"
|
||||
:icon="stepItem.icon"
|
||||
:pack="stepItem.iconPack"
|
||||
:size="size"/>
|
||||
</div>
|
||||
<div class="step-details">
|
||||
<span class="step-title">{{ stepItem.label }}</span>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<section class="step-content" :class="{'is-transitioning': isTransitioning}">
|
||||
<slot/>
|
||||
</section>
|
||||
<nav v-if="hasNavigation" class="step-navigation">
|
||||
<a
|
||||
role="button"
|
||||
href="#"
|
||||
class="pagination-previous"
|
||||
:disabled="!hasPrev"
|
||||
@click.prevent="prev"
|
||||
:aria-label="ariaPreviousLabel">
|
||||
<b-icon
|
||||
icon="chevron-left"
|
||||
:pack="iconPack"
|
||||
both
|
||||
aria-hidden="true"/>
|
||||
</a>
|
||||
<a
|
||||
role="button"
|
||||
href="#"
|
||||
class="pagination-next"
|
||||
:disabled="!hasNext"
|
||||
@click.prevent="next"
|
||||
:aria-label="ariaNextLabel">
|
||||
<b-icon
|
||||
icon="chevron-right"
|
||||
:pack="iconPack"
|
||||
both
|
||||
aria-hidden="true"/>
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Icon from '../icon/Icon'
|
||||
import SlotComponent from '../../utils/SlotComponent'
|
||||
|
||||
export default {
|
||||
name: 'BSteps',
|
||||
components: {
|
||||
[Icon.name]: Icon,
|
||||
[SlotComponent.name]: SlotComponent
|
||||
},
|
||||
props: {
|
||||
value: Number,
|
||||
type: String | Object,
|
||||
size: String,
|
||||
animated: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
destroyOnHide: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
iconPack: String,
|
||||
hasNavigation: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
ariaNextLabel: String,
|
||||
ariaPreviousLabel: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeStep: this.value || 0,
|
||||
stepItems: [],
|
||||
contentHeight: 0,
|
||||
isTransitioning: false,
|
||||
_isSteps: true // Used internally by StepItem
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
mainClasses() {
|
||||
return [
|
||||
this.type,
|
||||
this.size
|
||||
]
|
||||
},
|
||||
|
||||
reversedStepItems() {
|
||||
return this.stepItems.slice().reverse()
|
||||
},
|
||||
|
||||
/**
|
||||
* Check the first visible step index.
|
||||
*/
|
||||
firstVisibleStepIndex() {
|
||||
return this.stepItems.findIndex((step, idx) => {
|
||||
return step.visible
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if previous button is available.
|
||||
*/
|
||||
hasPrev() {
|
||||
return this.firstVisibleStepIndex >= 0 &&
|
||||
this.activeStep > this.firstVisibleStepIndex
|
||||
},
|
||||
|
||||
/**
|
||||
* Check the last visible step index.
|
||||
*/
|
||||
lastVisibleStepIndex() {
|
||||
let idx = this.reversedStepItems.findIndex((step, idx) => {
|
||||
return step.visible
|
||||
})
|
||||
if (idx >= 0) {
|
||||
return this.stepItems.length - 1 - idx
|
||||
}
|
||||
return idx
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if next button is available.
|
||||
*/
|
||||
hasNext() {
|
||||
return this.lastVisibleStepIndex >= 0 &&
|
||||
this.activeStep < this.lastVisibleStepIndex
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
/**
|
||||
* When v-model is changed set the new active step.
|
||||
*/
|
||||
value(value) {
|
||||
this.changeStep(value)
|
||||
},
|
||||
|
||||
/**
|
||||
* When step-items are updated, set active one.
|
||||
*/
|
||||
stepItems() {
|
||||
if (this.activeStep < this.stepItems.length) {
|
||||
this.stepItems[this.activeStep].isActive = true
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* Change the active step and emit change event.
|
||||
*/
|
||||
changeStep(newIndex) {
|
||||
if (this.activeStep === newIndex) return
|
||||
|
||||
if (this.activeStep < this.stepItems.length) {
|
||||
this.stepItems[this.activeStep].deactivate(this.activeStep, newIndex)
|
||||
}
|
||||
this.stepItems[newIndex].activate(this.activeStep, newIndex)
|
||||
this.activeStep = newIndex
|
||||
this.$emit('change', newIndex)
|
||||
},
|
||||
|
||||
/**
|
||||
* Return if the step should be clickable or not.
|
||||
*/
|
||||
isItemClickable(stepItem) {
|
||||
if (stepItem.clickable === undefined) {
|
||||
return stepItem.completed
|
||||
}
|
||||
return stepItem.clickable
|
||||
},
|
||||
|
||||
/**
|
||||
* Step click listener, emit input event and change active step.
|
||||
*/
|
||||
stepClick(value) {
|
||||
this.$emit('input', value)
|
||||
this.changeStep(value)
|
||||
},
|
||||
|
||||
/**
|
||||
* Previous button click listener.
|
||||
*/
|
||||
prev() {
|
||||
if (!this.hasPrev) return
|
||||
let prevItemIdx = this.reversedStepItems.findIndex((step, idx) => {
|
||||
return this.stepItems.length - 1 - idx < this.activeStep && step.visible
|
||||
})
|
||||
if (prevItemIdx >= 0) {
|
||||
prevItemIdx = this.stepItems.length - 1 - prevItemIdx
|
||||
}
|
||||
this.changeStep(prevItemIdx)
|
||||
},
|
||||
|
||||
/**
|
||||
* Previous button click listener.
|
||||
*/
|
||||
next() {
|
||||
if (!this.hasNext) return
|
||||
const nextItemIdx = this.stepItems.findIndex((step, idx) => {
|
||||
return idx > this.activeStep && step.visible
|
||||
})
|
||||
this.changeStep(nextItemIdx)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.activeStep < this.stepItems.length) {
|
||||
this.stepItems[this.activeStep].isActive = true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
import Steps from './Steps'
|
||||
import StepItem from './StepItem'
|
||||
|
||||
import { use, registerComponent } from '../../utils/plugins'
|
||||
|
||||
const Plugin = {
|
||||
install(Vue) {
|
||||
registerComponent(Vue, Steps)
|
||||
registerComponent(Vue, StepItem)
|
||||
}
|
||||
}
|
||||
|
||||
use(Plugin)
|
||||
|
||||
export default Plugin
|
||||
|
||||
export {
|
||||
Steps,
|
||||
StepItem
|
||||
}
|
||||
+13
-5
@@ -20,10 +20,12 @@
|
||||
<tr>
|
||||
<th v-if="showDetailRowIcon" width="40px"/>
|
||||
<th class="checkbox-cell" v-if="checkable">
|
||||
<b-checkbox
|
||||
:value="isAllChecked"
|
||||
:disabled="isAllUncheckable"
|
||||
@change.native="checkAll"/>
|
||||
<template v-if="headerCheckable">
|
||||
<b-checkbox
|
||||
:value="isAllChecked"
|
||||
:disabled="isAllUncheckable"
|
||||
@change.native="checkAll"/>
|
||||
</template>
|
||||
</th>
|
||||
<th
|
||||
v-for="(column, index) in visibleColumns"
|
||||
@@ -32,7 +34,9 @@
|
||||
'is-current-sort': currentSortColumn === column,
|
||||
'is-sortable': column.sortable
|
||||
}"
|
||||
:style="{ width: column.width + 'px' }"
|
||||
:style="{
|
||||
width: column.width === undefined ? null : column.width + 'px'
|
||||
}"
|
||||
@click.stop="sort(column)">
|
||||
<div
|
||||
class="th-wrap"
|
||||
@@ -223,6 +227,10 @@
|
||||
loading: Boolean,
|
||||
detailed: Boolean,
|
||||
checkable: Boolean,
|
||||
headerCheckable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
selected: Object,
|
||||
focusable: Boolean,
|
||||
customIsChecked: Function,
|
||||
|
||||
+13
@@ -16,6 +16,7 @@
|
||||
:disabled="disabled"
|
||||
:ellipsis="ellipsis"
|
||||
:closable="closable"
|
||||
:title="ellipsis && getNormalizedTagText(tag)"
|
||||
@close="removeTag(index)">
|
||||
{{ getNormalizedTagText(tag) }}
|
||||
</b-tag>
|
||||
@@ -36,6 +37,7 @@
|
||||
:loading="loading"
|
||||
:autocomplete="nativeAutocomplete"
|
||||
:keep-first="!allowNew"
|
||||
:use-html5-validation="useHtml5Validation"
|
||||
@typing="onTyping"
|
||||
@focus="onFocus"
|
||||
@blur="customOnBlur"
|
||||
@@ -54,6 +56,9 @@
|
||||
<template :slot="emptySlotName">
|
||||
<slot name="empty" />
|
||||
</template>
|
||||
<template :slot="footerSlotName">
|
||||
<slot name="footer" />
|
||||
</template>
|
||||
</b-autocomplete>
|
||||
</div>
|
||||
|
||||
@@ -176,6 +181,10 @@
|
||||
return this.hasHeaderSlot ? 'header' : 'dontrender'
|
||||
},
|
||||
|
||||
footerSlotName() {
|
||||
return this.hasHeaderSlot ? 'footer' : 'dontrender'
|
||||
},
|
||||
|
||||
hasDefaultSlot() {
|
||||
return !!this.$scopedSlots.default
|
||||
},
|
||||
@@ -188,6 +197,10 @@
|
||||
return !!this.$slots.header
|
||||
},
|
||||
|
||||
hasFooterSlot() {
|
||||
return !!this.$slots.footer
|
||||
},
|
||||
|
||||
/**
|
||||
* Show the input field if a maxtags hasn't been set or reached.
|
||||
*/
|
||||
|
||||
+27
-8
@@ -11,7 +11,7 @@
|
||||
ref="input"
|
||||
slot="trigger"
|
||||
autocomplete="off"
|
||||
:value="formatValue(dateSelected)"
|
||||
:value="formatValue(computedValue)"
|
||||
:placeholder="placeholder"
|
||||
:size="size"
|
||||
:icon="icon"
|
||||
@@ -21,9 +21,11 @@
|
||||
:readonly="!editable"
|
||||
:rounded="rounded"
|
||||
v-bind="$attrs"
|
||||
:use-html5-validation="useHtml5Validation"
|
||||
@keyup.native.enter="toggle(true)"
|
||||
@change.native="onChange($event.target.value)"
|
||||
@focus="$emit('focus', $event)"
|
||||
@blur="$emit('blur', $event) && checkHtml5Validity()"/>
|
||||
@focus="handleOnFocus"
|
||||
@blur="onBlur() && checkHtml5Validity()"/>
|
||||
|
||||
<b-dropdown-item :disabled="disabled" custom>
|
||||
<b-field grouped position="is-centered">
|
||||
@@ -54,6 +56,22 @@
|
||||
{{ minute.label }}
|
||||
</option>
|
||||
</b-select>
|
||||
<template v-if="enableSeconds">
|
||||
<span class="control is-colon">:</span>
|
||||
<b-select
|
||||
v-model="secondsSelected"
|
||||
@change.native="onSecondsChange($event.target.value)"
|
||||
:disabled="disabled"
|
||||
placeholder="00">
|
||||
<option
|
||||
v-for="second in seconds"
|
||||
:value="second.value"
|
||||
:key="second.value"
|
||||
:disabled="isSecondDisabled(second.value)">
|
||||
{{ second.label }}
|
||||
</option>
|
||||
</b-select>
|
||||
</template>
|
||||
<b-select
|
||||
v-model="meridienSelected"
|
||||
@change.native="onMeridienChange($event.target.value)"
|
||||
@@ -81,7 +99,7 @@
|
||||
ref="input"
|
||||
type="time"
|
||||
autocomplete="off"
|
||||
:value="formatHHMMSS(value)"
|
||||
:value="formatHHMMSS(computedValue)"
|
||||
:placeholder="placeholder"
|
||||
:size="size"
|
||||
:icon="icon"
|
||||
@@ -92,14 +110,15 @@
|
||||
:disabled="disabled"
|
||||
:readonly="false"
|
||||
v-bind="$attrs"
|
||||
@change.native="onChangeNativePicker"
|
||||
@focus="$emit('focus', $event)"
|
||||
@blur="$emit('blur', $event) && checkHtml5Validity()"/>
|
||||
:use-html5-validation="useHtml5Validation"
|
||||
@change.native="onChange($event.target.value)"
|
||||
@focus="handleOnFocus"
|
||||
@blur="onBlur() && checkHtml5Validity()"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { default as TimepickerMixin } from '../../utils/TimepickerMixin'
|
||||
import TimepickerMixin from '../../utils/TimepickerMixin'
|
||||
import Dropdown from '../dropdown/Dropdown'
|
||||
import DropdownItem from '../dropdown/DropdownItem'
|
||||
import Input from '../input/Input'
|
||||
|
||||
+1
@@ -27,6 +27,7 @@
|
||||
:multiple="multiple"
|
||||
:accept="accept"
|
||||
:disabled="disabled"
|
||||
:use-html5-validation="useHtml5Validation"
|
||||
@change="onFileChange">
|
||||
</label>
|
||||
</template>
|
||||
|
||||
+1
@@ -17,6 +17,7 @@
|
||||
@import "components/_pagination";
|
||||
@import "components/_radio";
|
||||
@import "components/_select";
|
||||
@import "components/_steps";
|
||||
@import "components/_switch";
|
||||
@import "components/_table";
|
||||
@import "components/_tabs";
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@ $checkbox-checkmark-color: $primary-invert !default;
|
||||
opacity: 0.5;
|
||||
}
|
||||
&:hover {
|
||||
input[type=checkbox] + .check {
|
||||
input[type=checkbox]:not(:disabled) + .check {
|
||||
border-color: $checkbox-active-background-color;
|
||||
@each $name, $pair in $colors {
|
||||
$color: nth($pair, 1);
|
||||
|
||||
+9
@@ -64,6 +64,15 @@
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.card {
|
||||
border-radius: $radius;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
border-top-left-radius: $radius;
|
||||
border-top-right-radius: $radius;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
padding: $padding-outer;
|
||||
}
|
||||
|
||||
+35
-19
@@ -13,7 +13,7 @@
|
||||
border-bottom: 1px solid $grey-lighter;
|
||||
}
|
||||
.datepicker-content {
|
||||
height: 16.25rem;
|
||||
height: 16.25rem;
|
||||
}
|
||||
.datepicker-footer {
|
||||
margin-top: 0.875rem;
|
||||
@@ -41,27 +41,43 @@
|
||||
display: table-row-group;
|
||||
.datepicker-row {
|
||||
display: table-row;
|
||||
}
|
||||
.datepicker-months {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
width: 17rem;
|
||||
.datepicker-cell {
|
||||
&.is-unselectable {
|
||||
color: $grey-light;
|
||||
}
|
||||
&.is-today {
|
||||
border: solid 1px rgba($primary, 0.5);
|
||||
}
|
||||
&.is-selectable {
|
||||
color: $grey-dark;
|
||||
&:hover:not(.is-selected),
|
||||
&:focus:not(.is-selected) {
|
||||
background-color: $background;
|
||||
color: $black;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
&.is-selected {
|
||||
background-color: $primary;
|
||||
color: $primary-invert;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 33.33%;
|
||||
height: 2.5rem;
|
||||
}
|
||||
}
|
||||
.datepicker-cell {
|
||||
&.is-unselectable {
|
||||
color: $grey-light;
|
||||
}
|
||||
&.is-today {
|
||||
border: solid 1px rgba($primary, 0.5);
|
||||
}
|
||||
&.is-selectable {
|
||||
color: $grey-dark;
|
||||
&:hover:not(.is-selected),
|
||||
&:focus:not(.is-selected) {
|
||||
background-color: $background;
|
||||
color: $black;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
&.is-selected {
|
||||
background-color: $primary;
|
||||
color: $primary-invert;
|
||||
}
|
||||
&.is-nearby:not(.is-selected) {
|
||||
color: $grey-light;
|
||||
}
|
||||
}
|
||||
&.has-events {
|
||||
.datepicker-cell {
|
||||
|
||||
+2
-1
@@ -6,7 +6,7 @@
|
||||
@include overlay;
|
||||
position: fixed;
|
||||
background-color: rgba($black, 0.86);
|
||||
z-index: 10;
|
||||
z-index: 40;
|
||||
cursor: pointer;
|
||||
@include desktop {
|
||||
display: none;
|
||||
@@ -89,6 +89,7 @@
|
||||
transform: translate3d(-50%, -25%, 0);
|
||||
white-space: normal;
|
||||
overflow-y: auto;
|
||||
z-index: 50;
|
||||
.dropdown-item {
|
||||
padding: 1rem 1.5rem;
|
||||
}
|
||||
|
||||
+114
-3
@@ -1,6 +1,4 @@
|
||||
.label {
|
||||
font-weight: $weight-semibold
|
||||
}
|
||||
$floating-in-height: 3.25em;
|
||||
|
||||
.field {
|
||||
&.is-grouped {
|
||||
@@ -43,6 +41,119 @@
|
||||
}
|
||||
}
|
||||
|
||||
.field {
|
||||
&.is-floating-label {
|
||||
position: relative;
|
||||
.label {
|
||||
position: absolute;
|
||||
top: -0.775em;
|
||||
left: 1em;
|
||||
font-size: calc(#{$size-normal} * 3 / 4);
|
||||
background-color: transparent;
|
||||
padding-left: 0.125em;
|
||||
padding-right: 0.125em;
|
||||
z-index: 5;
|
||||
&:before {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0.775em;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 0.375em;
|
||||
background-color: #fff;
|
||||
z-index: -1;
|
||||
}
|
||||
&.is-small {
|
||||
font-size: calc(#{$size-small} * 3 / 4);
|
||||
}
|
||||
&.is-medium {
|
||||
font-size: calc(#{$size-medium} * 3 / 4);
|
||||
}
|
||||
&.is-large {
|
||||
font-size: calc(#{$size-large} * 3 / 4);
|
||||
}
|
||||
}
|
||||
.input,
|
||||
.textarea,
|
||||
.select
|
||||
select {
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
.taginput .taginput-container.is-focusable {
|
||||
padding-top: 0.475em;
|
||||
&.is-focused {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.is-floating-in-label {
|
||||
position: relative;
|
||||
.label {
|
||||
position: absolute;
|
||||
top: 0.25em;
|
||||
left: 1em;
|
||||
font-size: calc(#{$size-normal} * 3 / 4);
|
||||
background-color: transparent;
|
||||
z-index: 5;
|
||||
&.is-small {
|
||||
font-size: calc(#{$size-small} * 3 / 4);
|
||||
}
|
||||
&.is-medium {
|
||||
font-size: calc(#{$size-medium} * 3 / 4);
|
||||
}
|
||||
&.is-large {
|
||||
font-size: calc(#{$size-large} * 3 / 4);
|
||||
}
|
||||
}
|
||||
> .datepicker, > .timepicker {
|
||||
.input {
|
||||
padding-top: calc(#{$floating-in-height} / 2 - (#{$size-large} * 3 / 4) / 2);
|
||||
padding-bottom: 1px;
|
||||
height: $floating-in-height;
|
||||
}
|
||||
}
|
||||
> :not(.datepicker):not(.timepicker):not(.taginput) {
|
||||
.input,
|
||||
.textarea,
|
||||
select {
|
||||
padding-top: calc(#{$floating-in-height} / 2 - (#{$size-large} * 3 / 4) / 2);
|
||||
padding-bottom: 1px;
|
||||
height: $floating-in-height;
|
||||
}
|
||||
.select:not(multiple) {
|
||||
height: $floating-in-height;
|
||||
&.is-loading {
|
||||
&::after {
|
||||
margin-top: calc(#{$floating-in-height} / 2 - (#{$size-large} * 3 / 4) / 2);
|
||||
}
|
||||
}
|
||||
&::after {
|
||||
margin-top: 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
> :not(.taginput) {
|
||||
.is-left.icon,
|
||||
.is-right.icon {
|
||||
height: $floating-in-height;
|
||||
}
|
||||
.is-left.icon {
|
||||
padding-top: calc(#{$floating-in-height} / 2 - (#{$size-large} * 3 / 4) / 2);
|
||||
}
|
||||
}
|
||||
.control.is-loading::after {
|
||||
margin-top: calc(#{$floating-in-height} / 2 - (#{$size-large} * 3 / 4) / 2);
|
||||
}
|
||||
.taginput .taginput-container.is-focusable {
|
||||
// 0.275em - 1px _taginput.scss
|
||||
padding-top: calc(#{$floating-in-height} / 2 - (#{$size-large} * 3 / 4) / 2 + (0.275em - 1px));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.control {
|
||||
.help.counter {
|
||||
float: right;
|
||||
|
||||
+10
@@ -1,4 +1,14 @@
|
||||
.modal {
|
||||
&.is-full-screen {
|
||||
.animation-content,
|
||||
.modal-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-height: 100vh;
|
||||
margin: 0;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
}
|
||||
.animation-content {
|
||||
margin: 0 20px;
|
||||
.modal-card {
|
||||
|
||||
+4
-6
@@ -2,11 +2,9 @@
|
||||
&.field {
|
||||
margin-bottom: 0;
|
||||
&.is-grouped {
|
||||
@include mobile {
|
||||
div.control {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
div.control {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,4 +24,4 @@
|
||||
padding-right: 0.75em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+21
-14
@@ -1,4 +1,5 @@
|
||||
$radio-active-background-color: $primary !default;
|
||||
$radio-size: 1.25em !default;
|
||||
|
||||
.b-radio {
|
||||
&.radio {
|
||||
@@ -16,23 +17,29 @@ $radio-active-background-color: $primary !default;
|
||||
outline: none;
|
||||
z-index: -1;
|
||||
+ .check {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
width: 1.25em;
|
||||
height: 1.25em;
|
||||
border: 2px solid $grey;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
width: $radio-size;
|
||||
height: $radio-size;
|
||||
transition: background $speed-slow $easing;
|
||||
border-radius: 50%;
|
||||
border: 2px solid $grey;
|
||||
&:before {
|
||||
content: "";
|
||||
border-radius: 50%;
|
||||
width: 0.625em;
|
||||
height: 0.625em;
|
||||
background: $radio-active-background-color;
|
||||
display: flex;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-left: calc(-#{$radio-size}/2);
|
||||
bottom: 50%;
|
||||
margin-bottom: calc(-#{$radio-size}/2);
|
||||
width: $radio-size;
|
||||
height: $radio-size;
|
||||
transition: transform $speed-slow $easing;
|
||||
border-radius: 50%;
|
||||
transform: scale(0);
|
||||
transition: transform $speed-slow $easing;
|
||||
background-color: $radio-active-background-color;
|
||||
}
|
||||
@each $name, $pair in $colors {
|
||||
$color: nth($pair, 1);
|
||||
@@ -50,7 +57,7 @@ $radio-active-background-color: $primary !default;
|
||||
}
|
||||
}
|
||||
&:before {
|
||||
transform: scale(1);
|
||||
transform: scale(.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,7 +68,7 @@ $radio-active-background-color: $primary !default;
|
||||
opacity: 0.5;
|
||||
}
|
||||
&:hover {
|
||||
input[type=radio] + .check {
|
||||
input[type=radio]:not(:disabled) + .check {
|
||||
border-color: $radio-active-background-color;
|
||||
@each $name, $pair in $colors {
|
||||
$color: nth($pair, 1);
|
||||
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
This project is based on
|
||||
"bulma-steps" (https://github.com/Wikiki/bulma-steps) by
|
||||
Wikiki (https://github.com/Wikiki) licensed under
|
||||
MIT (https://github.com/Wikiki/bulma-steps/blob/master/LICENSE)
|
||||
*/
|
||||
|
||||
$steps-maker-default-color: $grey-light !default;
|
||||
$steps-marker-default-border: .2em solid #fff !default;
|
||||
$steps-default-color: $grey-lighter !default;
|
||||
$steps-completed-color: $primary !default;
|
||||
$steps-active-color: $primary !default;
|
||||
$steps-divider-height: .2em !default;
|
||||
|
||||
@mixin steps-size($size) {
|
||||
font-size: $size;
|
||||
min-height: $size * 2;
|
||||
|
||||
.step-items {
|
||||
.step-item {
|
||||
.step-marker {
|
||||
height: $size * 2;
|
||||
width: $size * 2;
|
||||
position: absolute;
|
||||
left: calc(50% - #{$size});
|
||||
|
||||
.icon {
|
||||
*, *:before {
|
||||
font-size: $size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.step-details {
|
||||
margin-top: $size * 2;
|
||||
margin-left: .5em;
|
||||
margin-right: .5em;
|
||||
padding-top: .2em;
|
||||
|
||||
.step-title {
|
||||
font-size: $size * 1.2;
|
||||
font-weight: $weight-semibold;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
&::before {
|
||||
height: $steps-divider-height;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
left: -50%;
|
||||
top: #{$size};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.b-steps {
|
||||
.steps {
|
||||
.step-items {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.step-item {
|
||||
margin-top: 0;
|
||||
position: relative;
|
||||
flex-grow: 1;
|
||||
flex-basis: 0;
|
||||
|
||||
.step-link {
|
||||
color: $body-color;
|
||||
|
||||
&:not(.is-clickable) {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.step-marker {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
border-radius: 50%;
|
||||
font-weight: $weight-bold;
|
||||
justify-content: center;
|
||||
background: $steps-maker-default-color;
|
||||
color: $white;
|
||||
border: $steps-marker-default-border;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
// Override marker color per step
|
||||
@each $name, $pair in $colors {
|
||||
$color: nth($pair, 1);
|
||||
$color-invert: nth($pair, 2);
|
||||
|
||||
&.is-#{$name} {
|
||||
&::before {
|
||||
background: linear-gradient(to left, $steps-default-color 50%, $color 50%);
|
||||
background-size: 200% 100%;
|
||||
background-position: right bottom;
|
||||
}
|
||||
&.is-active {
|
||||
.step-marker {
|
||||
background-color: $white;
|
||||
border-color: $color;
|
||||
color: $color;
|
||||
}
|
||||
|
||||
&::before {
|
||||
background-position: left bottom;
|
||||
}
|
||||
}
|
||||
&.is-completed {
|
||||
.step-marker {
|
||||
color: $color-invert;
|
||||
background-color: $color;
|
||||
}
|
||||
|
||||
&::before {
|
||||
background-position: left bottom;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.step-marker{
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.step-details {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
flex-basis: 1em;
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
|
||||
&::before {
|
||||
// This will contain the divider
|
||||
content: " ";
|
||||
display: block;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
&::before {
|
||||
background: linear-gradient(to left, $steps-default-color 50%, $steps-active-color 50%);
|
||||
background-size: 200% 100%;
|
||||
background-position: right bottom;
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
.step-link {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.step-marker {
|
||||
background-color: $white;
|
||||
border-color: $steps-active-color;
|
||||
color: $steps-active-color;
|
||||
}
|
||||
|
||||
&::before {
|
||||
background-position: left bottom;
|
||||
}
|
||||
}
|
||||
&.is-completed {
|
||||
.step-marker {
|
||||
color: $white;
|
||||
background-color: $steps-completed-color;
|
||||
}
|
||||
|
||||
&::before {
|
||||
background-position: left bottom;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ .step-content {
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1rem;
|
||||
.step-item {
|
||||
flex-shrink: 0;
|
||||
flex-basis: auto;
|
||||
}
|
||||
&.is-transitioning {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
@include steps-size($size-normal);
|
||||
&.is-small {
|
||||
@include steps-size($size-small);
|
||||
}
|
||||
&.is-medium {
|
||||
@include steps-size($size-medium);
|
||||
}
|
||||
&.is-large {
|
||||
@include steps-size($size-large);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*.b-tabs {
|
||||
.tabs {
|
||||
margin-bottom: 0;
|
||||
flex-shrink: 0;
|
||||
li {
|
||||
&.is-disabled {
|
||||
pointer-events: none;
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
.tab-content {
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1rem;
|
||||
.tab-item {
|
||||
flex-shrink: 0;
|
||||
flex-basis: auto;
|
||||
}
|
||||
&.is-transitioning {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
&.is-fullwidth {
|
||||
width: 100%;
|
||||
}
|
||||
}*/
|
||||
+7
-5
@@ -2,11 +2,13 @@
|
||||
.tabs {
|
||||
margin-bottom: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.is-disabled {
|
||||
pointer-events: none;
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
li {
|
||||
&.is-disabled {
|
||||
pointer-events: none;
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
.tab-content {
|
||||
position: relative;
|
||||
|
||||
+2
-1
@@ -6,6 +6,7 @@ $taginput-height: 1.7em;
|
||||
@extend .input;
|
||||
padding-bottom: 0;
|
||||
padding-top: calc(0.275em - 1px);
|
||||
padding-left: 0;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@@ -25,7 +26,7 @@ $taginput-height: 1.7em;
|
||||
height: $taginput-height;
|
||||
}
|
||||
&:not(:last-child) {
|
||||
margin-right: 0.275rem;
|
||||
margin-left: 0.275rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -11,3 +11,4 @@ $link-invert: $primary-invert !default;
|
||||
$link-visited: $grey !default;
|
||||
$link-focus-border: $primary !default;
|
||||
|
||||
$label-weight: $weight-semibold !default;
|
||||
|
||||
+3
-2
@@ -14,7 +14,8 @@ export default {
|
||||
useHtml5Validation: {
|
||||
type: Boolean,
|
||||
default: () => config.defaultUseHtml5Validation
|
||||
}
|
||||
},
|
||||
validationMessage: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -117,7 +118,7 @@ export default {
|
||||
let isValid = true
|
||||
if (!el.checkValidity()) {
|
||||
type = 'is-danger'
|
||||
message = el.validationMessage
|
||||
message = this.validationMessage || el.validationMessage
|
||||
isValid = false
|
||||
}
|
||||
this.isValid = isValid
|
||||
|
||||
+250
-127
@@ -7,6 +7,62 @@ const PM = 'PM'
|
||||
const HOUR_FORMAT_24 = '24'
|
||||
const HOUR_FORMAT_12 = '12'
|
||||
|
||||
const defaultTimeFormatter = (date, vm) => {
|
||||
let hours = date.getHours()
|
||||
const minutes = date.getMinutes()
|
||||
const seconds = date.getSeconds()
|
||||
let period = ''
|
||||
if (vm.hourFormat === HOUR_FORMAT_12) {
|
||||
period = ' ' + (hours < 12 ? AM : PM)
|
||||
if (hours > 12) {
|
||||
hours -= 12
|
||||
} else if (hours === 0) {
|
||||
hours = 12
|
||||
}
|
||||
}
|
||||
return vm.pad(hours) + ':' + vm.pad(minutes) +
|
||||
(vm.enableSeconds ? (':' + vm.pad(seconds)) : '') + period
|
||||
}
|
||||
|
||||
const defaultTimeParser = (timeString, vm) => {
|
||||
if (timeString) {
|
||||
let am = false
|
||||
if (vm.hourFormat === HOUR_FORMAT_12) {
|
||||
const dateString12 = timeString.split(' ')
|
||||
timeString = dateString12[0]
|
||||
am = dateString12[1] === AM
|
||||
}
|
||||
const time = timeString.split(':')
|
||||
let hours = parseInt(time[0], 10)
|
||||
const minutes = parseInt(time[1], 10)
|
||||
const seconds = vm.enableSeconds ? parseInt(time[2], 10) : 0
|
||||
if (isNaN(hours) || hours < 0 || hours > 23 ||
|
||||
(vm.hourFormat === HOUR_FORMAT_12 && (hours < 1 || hours > 12)) ||
|
||||
isNaN(minutes) || minutes < 0 || minutes > 59) {
|
||||
return null
|
||||
}
|
||||
let d = null
|
||||
if (vm.computedValue && !isNaN(vm.computedValue)) {
|
||||
d = new Date(vm.computedValue)
|
||||
} else {
|
||||
d = new Date()
|
||||
d.setMilliseconds(0)
|
||||
}
|
||||
d.setSeconds(seconds)
|
||||
d.setMinutes(minutes)
|
||||
if (this.hourFormat === HOUR_FORMAT_12) {
|
||||
if (am && hours === 12) {
|
||||
hours = 0
|
||||
} else if (!am && hours !== 12) {
|
||||
hours += 12
|
||||
}
|
||||
}
|
||||
d.setHours(hours)
|
||||
return new Date(d.geTime())
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export default {
|
||||
mixins: [FormElementMixin],
|
||||
inheritAttrs: false,
|
||||
@@ -29,16 +85,28 @@ export default {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
incrementSeconds: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
timeFormatter: {
|
||||
type: Function,
|
||||
default: (date) => {
|
||||
this.formatTime(date)
|
||||
default: (date, vm) => {
|
||||
if (typeof config.defaultTimeFormatter === 'function') {
|
||||
return config.defaultTimeFormatter(date)
|
||||
} else {
|
||||
return defaultTimeFormatter(date, vm)
|
||||
}
|
||||
}
|
||||
},
|
||||
timeParser: {
|
||||
type: Function,
|
||||
default: (date) => {
|
||||
this.parseTime(date)
|
||||
default: (date, vm) => {
|
||||
if (typeof config.defaultTimeParser === 'function') {
|
||||
return config.defaultTimeParser(date)
|
||||
} else {
|
||||
return defaultTimeParser(date, vm)
|
||||
}
|
||||
}
|
||||
},
|
||||
mobileNative: {
|
||||
@@ -48,13 +116,16 @@ export default {
|
||||
}
|
||||
},
|
||||
position: String,
|
||||
unselectableTimes: Array
|
||||
unselectableTimes: Array,
|
||||
openOnFocus: Boolean,
|
||||
enableSeconds: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dateSelected: this.value,
|
||||
hoursSelected: null,
|
||||
minutesSelected: null,
|
||||
secondsSelected: null,
|
||||
meridienSelected: null,
|
||||
_elementRef: 'input',
|
||||
AM,
|
||||
@@ -64,6 +135,15 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
computedValue: {
|
||||
get() {
|
||||
return this.dateSelected
|
||||
},
|
||||
set(value) {
|
||||
this.dateSelected = value
|
||||
this.$emit('input', value)
|
||||
}
|
||||
},
|
||||
hours() {
|
||||
const hours = []
|
||||
const numberOfHours = this.isHourFormat24 ? 24 : 12
|
||||
@@ -101,6 +181,18 @@ export default {
|
||||
}
|
||||
return minutes
|
||||
},
|
||||
|
||||
seconds() {
|
||||
const seconds = []
|
||||
for (let i = 0; i < 60; i += this.incrementSeconds) {
|
||||
seconds.push({
|
||||
label: this.formatNumber(i),
|
||||
value: i
|
||||
})
|
||||
}
|
||||
return seconds
|
||||
},
|
||||
|
||||
meridiens() {
|
||||
return [AM, PM]
|
||||
},
|
||||
@@ -114,30 +206,22 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
||||
hourFormat(value) {
|
||||
hourFormat() {
|
||||
if (this.hoursSelected !== null) {
|
||||
this.meridienSelected = this.hoursSelected >= 12 ? PM : AM
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Emit input event with selected date as payload.
|
||||
*/
|
||||
dateSelected(value) {
|
||||
this.$emit('input', value)
|
||||
},
|
||||
|
||||
},
|
||||
/**
|
||||
* When v-model is changed:
|
||||
* 1. Update internal value.
|
||||
* 2. If it's invalid, validate again.
|
||||
*/
|
||||
value(value) {
|
||||
this.updateInternalState(value)
|
||||
this.dateSelected = value
|
||||
|
||||
!this.isValid && this.$refs.input.checkHtml5Validity()
|
||||
value: {
|
||||
handler(value) {
|
||||
this.updateInternalState(value)
|
||||
!this.isValid && this.$refs.input.checkHtml5Validity()
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -149,13 +233,18 @@ export default {
|
||||
this.hoursSelected -= 12
|
||||
}
|
||||
}
|
||||
this.updateDateSelected(this.hoursSelected, this.minutesSelected, value)
|
||||
this.updateDateSelected(
|
||||
this.hoursSelected,
|
||||
this.minutesSelected,
|
||||
this.enableSeconds ? this.secondsSelected : 0,
|
||||
value)
|
||||
},
|
||||
|
||||
onHoursChange(value) {
|
||||
this.updateDateSelected(
|
||||
parseInt(value, 10),
|
||||
this.minutesSelected,
|
||||
this.enableSeconds ? this.secondsSelected : 0,
|
||||
this.meridienSelected
|
||||
)
|
||||
},
|
||||
@@ -164,22 +253,34 @@ export default {
|
||||
this.updateDateSelected(
|
||||
this.hoursSelected,
|
||||
parseInt(value, 10),
|
||||
this.enableSeconds ? this.secondsSelected : 0,
|
||||
this.meridienSelected
|
||||
)
|
||||
},
|
||||
|
||||
onSecondsChange(value) {
|
||||
this.updateDateSelected(
|
||||
this.hoursSelected,
|
||||
this.minutesSelected,
|
||||
parseInt(value, 10),
|
||||
this.meridienSelected
|
||||
)
|
||||
},
|
||||
|
||||
updateDateSelected(hours, minutes, meridiens) {
|
||||
updateDateSelected(hours, minutes, seconds, meridiens) {
|
||||
if (hours != null && minutes != null &&
|
||||
((!this.isHourFormat24 && meridiens !== null) || this.isHourFormat24)) {
|
||||
if (this.dateSelected && !isNaN(this.dateSelected)) {
|
||||
this.dateSelected = new Date(this.dateSelected)
|
||||
let time = null
|
||||
if (this.computedValue && !isNaN(this.computedValue)) {
|
||||
time = new Date(this.computedValue)
|
||||
} else {
|
||||
this.dateSelected = new Date()
|
||||
this.dateSelected.setMilliseconds(0)
|
||||
this.dateSelected.setSeconds(0)
|
||||
time = new Date()
|
||||
time.setMilliseconds(0)
|
||||
}
|
||||
this.dateSelected.setHours(hours)
|
||||
this.dateSelected.setMinutes(minutes)
|
||||
time.setHours(hours)
|
||||
time.setMinutes(minutes)
|
||||
time.setSeconds(seconds)
|
||||
this.computedValue = new Date(time.getTime())
|
||||
}
|
||||
},
|
||||
|
||||
@@ -187,12 +288,15 @@ export default {
|
||||
if (value) {
|
||||
this.hoursSelected = value.getHours()
|
||||
this.minutesSelected = value.getMinutes()
|
||||
this.secondsSelected = value.getSeconds()
|
||||
this.meridienSelected = value.getHours() >= 12 ? PM : AM
|
||||
} else {
|
||||
this.hoursSelected = null
|
||||
this.minutesSelected = null
|
||||
this.secondsSelected = null
|
||||
this.meridienSelected = AM
|
||||
}
|
||||
this.dateSelected = value
|
||||
},
|
||||
|
||||
isHourDisabled(hour) {
|
||||
@@ -209,18 +313,19 @@ export default {
|
||||
}
|
||||
if (this.unselectableTimes) {
|
||||
if (!disabled) {
|
||||
if (this.minutesSelected !== null) {
|
||||
const unselectable = this.unselectableTimes.filter((time) => {
|
||||
const unselectable = this.unselectableTimes.filter((time) => {
|
||||
if (this.enableSeconds && this.secondsSelected !== null) {
|
||||
return time.getHours() === hour &&
|
||||
time.getMinutes() === this.minutesSelected &&
|
||||
time.getSeconds() === this.secondsSelected
|
||||
} else if (this.minutesSelected !== null) {
|
||||
return time.getHours() === hour &&
|
||||
time.getMinutes() === this.minutesSelected
|
||||
})
|
||||
disabled = unselectable.length > 0
|
||||
} else {
|
||||
const unselectable = this.unselectableTimes.filter((time) => {
|
||||
} else {
|
||||
return time.getHours() === hour
|
||||
})
|
||||
disabled = unselectable.length === this.minutes.length
|
||||
}
|
||||
}
|
||||
})
|
||||
disabled = unselectable.length > 0
|
||||
}
|
||||
}
|
||||
return disabled
|
||||
@@ -240,8 +345,52 @@ export default {
|
||||
if (this.maxTime) {
|
||||
if (!disabled) {
|
||||
const maxHours = this.maxTime.getHours()
|
||||
const minMinutes = this.maxTime.getMinutes()
|
||||
disabled = this.hoursSelected === maxHours && minute > minMinutes
|
||||
const maxMinutes = this.maxTime.getMinutes()
|
||||
disabled = this.hoursSelected === maxHours && minute > maxMinutes
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.unselectableTimes) {
|
||||
if (!disabled) {
|
||||
const unselectable = this.unselectableTimes.filter((time) => {
|
||||
if (this.enableSeconds && this.secondsSelected !== null) {
|
||||
return time.getHours() === this.hoursSelected &&
|
||||
time.getMinutes() === minute &&
|
||||
time.getSeconds() === this.secondsSelected
|
||||
} else {
|
||||
return time.getHours() === this.hoursSelected &&
|
||||
time.getMinutes() === minute
|
||||
}
|
||||
})
|
||||
disabled = unselectable.length > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
return disabled
|
||||
},
|
||||
|
||||
isSecondDisabled(second) {
|
||||
let disabled = false
|
||||
if (this.minutesSelected !== null) {
|
||||
if (this.isMinuteDisabled(this.minutesSelected)) {
|
||||
disabled = true
|
||||
} else {
|
||||
if (this.minTime) {
|
||||
const minHours = this.minTime.getHours()
|
||||
const minMinutes = this.minTime.getMinutes()
|
||||
const minSeconds = this.minTime.getSeconds()
|
||||
disabled = this.hoursSelected === minHours &&
|
||||
this.minutesSelected === minMinutes &&
|
||||
second < minSeconds
|
||||
}
|
||||
if (this.maxTime) {
|
||||
if (!disabled) {
|
||||
const maxHours = this.maxTime.getHours()
|
||||
const maxMinutes = this.maxTime.getMinutes()
|
||||
const maxSeconds = this.maxTime.getSeconds()
|
||||
disabled = this.hoursSelected === maxHours &&
|
||||
this.minutesSelected === maxMinutes &&
|
||||
second > maxSeconds
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -249,7 +398,8 @@ export default {
|
||||
if (!disabled) {
|
||||
const unselectable = this.unselectableTimes.filter((time) => {
|
||||
return time.getHours() === this.hoursSelected &&
|
||||
time.getMinutes() === minute
|
||||
time.getMinutes() === this.minutesSelected &&
|
||||
time.getSeconds() === second
|
||||
})
|
||||
disabled = unselectable.length > 0
|
||||
}
|
||||
@@ -262,23 +412,42 @@ export default {
|
||||
* Parse string into date
|
||||
*/
|
||||
onChange(value) {
|
||||
const date = this.parseTime(value)
|
||||
const date = this.timeParser(value, this)
|
||||
this.updateInternalState(date)
|
||||
if (date && !isNaN(date)) {
|
||||
this.dateSelected = date
|
||||
this.computedValue = date
|
||||
} else {
|
||||
// Force refresh input value when not valid date
|
||||
this.dateSelected = null
|
||||
this.$refs.input.newValue = this.dateSelected
|
||||
this.computedValue = null
|
||||
this.$refs.input.newValue = this.computedValue
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Close dropdown time picker
|
||||
* Toggle timepicker
|
||||
*/
|
||||
close() {
|
||||
toggle(active) {
|
||||
if (this.$refs.dropdown) {
|
||||
this.$refs.dropdown.isActive = false
|
||||
this.$refs.dropdown.isActive = typeof active === 'boolean'
|
||||
? active
|
||||
: !this.$refs.dropdown.isActive
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Close timepicker
|
||||
*/
|
||||
close() {
|
||||
this.toggle(false)
|
||||
},
|
||||
|
||||
/*
|
||||
* Call default onFocus method and show timepicker
|
||||
*/
|
||||
handleOnFocus() {
|
||||
this.onFocus()
|
||||
if (this.openOnFocus) {
|
||||
this.toggle(true)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -290,8 +459,10 @@ export default {
|
||||
if (value && !isNaN(date)) {
|
||||
const hours = date.getHours()
|
||||
const minutes = date.getMinutes()
|
||||
const seconds = date.getSeconds()
|
||||
return this.formatNumber(hours) + ':' +
|
||||
this.formatNumber(minutes, true) + ':00'
|
||||
this.formatNumber(minutes, true) + ':' +
|
||||
this.formatNumber(seconds, true)
|
||||
}
|
||||
return ''
|
||||
},
|
||||
@@ -302,18 +473,20 @@ export default {
|
||||
onChangeNativePicker(event) {
|
||||
const date = event.target.value
|
||||
if (date) {
|
||||
if (this.dateSelected && !isNaN(this.dateSelected)) {
|
||||
this.dateSelected = new Date(this.dateSelected)
|
||||
let time = null
|
||||
if (this.computedValue && !isNaN(this.computedValue)) {
|
||||
time = new Date(this.computedValue)
|
||||
} else {
|
||||
this.dateSelected = new Date()
|
||||
this.dateSelected.setMilliseconds(0)
|
||||
this.dateSelected.setSeconds(0)
|
||||
time = new Date()
|
||||
time.setMilliseconds(0)
|
||||
}
|
||||
const time = date.split(':')
|
||||
this.dateSelected.setHours(parseInt(time[0], 10))
|
||||
this.dateSelected.setMinutes(parseInt(time[1], 10))
|
||||
const t = date.split(':')
|
||||
time.setHours(parseInt(t[0], 10))
|
||||
time.setMinutes(parseInt(t[1], 10))
|
||||
time.setSeconds(t[2] ? parseInt(t[2], 10) : 0)
|
||||
this.computedValue = new Date(time.getTime())
|
||||
} else {
|
||||
this.dateSelected = null
|
||||
this.computedValue = null
|
||||
}
|
||||
},
|
||||
|
||||
@@ -332,79 +505,29 @@ export default {
|
||||
*/
|
||||
formatValue(date) {
|
||||
if (date && !isNaN(date)) {
|
||||
return this.formatTime(date)
|
||||
return this.timeFormatter(date, this)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
},
|
||||
|
||||
formatTime(date) {
|
||||
if (typeof config.defaultTimeFormatter === 'function') {
|
||||
return config.defaultTimeFormatter(date)
|
||||
} else {
|
||||
return this.defaultTimeFormatter(date)
|
||||
}
|
||||
},
|
||||
parseTime(date) {
|
||||
if (typeof config.defaultTimeParser === 'function') {
|
||||
return config.defaultTimeParser(date)
|
||||
} else {
|
||||
return this.defaultTimeParser(date)
|
||||
}
|
||||
},
|
||||
defaultTimeFormatter(date) {
|
||||
let hours = date.getHours()
|
||||
const minutes = date.getMinutes()
|
||||
let period = ''
|
||||
if (this.hourFormat === HOUR_FORMAT_12) {
|
||||
period = ' ' + (hours < 12 ? AM : PM)
|
||||
if (hours > 12) {
|
||||
hours -= 12
|
||||
} else if (hours === 0) {
|
||||
hours = 12
|
||||
}
|
||||
}
|
||||
return this.pad(hours) + ':' + this.pad(minutes) + period
|
||||
},
|
||||
defaultTimeParser(timeString) {
|
||||
if (timeString) {
|
||||
let am = false
|
||||
if (this.hourFormat === HOUR_FORMAT_12) {
|
||||
const dateString12 = timeString.split(' ')
|
||||
timeString = dateString12[0]
|
||||
am = dateString12[1] === AM
|
||||
}
|
||||
const time = timeString.split(':')
|
||||
let hours = parseInt(time[0], 10)
|
||||
const minutes = parseInt(time[1], 10)
|
||||
if (isNaN(hours) || hours < 0 || hours > 23 ||
|
||||
(this.hourFormat === HOUR_FORMAT_12 && (hours < 1 || hours > 12)) ||
|
||||
isNaN(minutes) || minutes < 0 || minutes > 59) {
|
||||
return null
|
||||
}
|
||||
let d = null
|
||||
if (this.dateSelected && !isNaN(this.dateSelected)) {
|
||||
d = new Date(this.dateSelected)
|
||||
} else {
|
||||
d = new Date()
|
||||
d.setMilliseconds(0)
|
||||
d.setSeconds(0)
|
||||
}
|
||||
d.setMinutes(minutes)
|
||||
if (this.hourFormat === HOUR_FORMAT_12) {
|
||||
if (am && hours === 12) {
|
||||
hours = 0
|
||||
} else if (!am && hours !== 12) {
|
||||
hours += 12
|
||||
}
|
||||
}
|
||||
d.setHours(hours)
|
||||
return d
|
||||
}
|
||||
return null
|
||||
/**
|
||||
* Keypress event that is bound to the document.
|
||||
*/
|
||||
keyPress(event) {
|
||||
// Esc key
|
||||
if (this.$refs.dropdown && this.$refs.dropdown.isActive && event.keyCode === 27) {
|
||||
this.toggle(false)
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.updateInternalState(this.value)
|
||||
created() {
|
||||
if (typeof window !== 'undefined') {
|
||||
document.addEventListener('keyup', this.keyPress)
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (typeof window !== 'undefined') {
|
||||
document.removeEventListener('keyup', this.keyPress)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-3
@@ -8,7 +8,7 @@ let config = {
|
||||
defaultSnackbarPosition: null,
|
||||
defaultToastDuration: 2000,
|
||||
defaultToastPosition: null,
|
||||
detaultNotificationDuration: 2000,
|
||||
defaultNotificationDuration: 2000,
|
||||
defaultNotificationPosition: null,
|
||||
defaultTooltipType: 'is-primary',
|
||||
defaultTooltipAnimated: false,
|
||||
@@ -22,13 +22,18 @@ let config = {
|
||||
defaultUnselectableDaysOfWeek: null,
|
||||
defaultTimeFormatter: null,
|
||||
defaultTimeParser: null,
|
||||
defaultModalCanCancel: null,
|
||||
defaultModalCanCancel: ['escape', 'x', 'outside', 'button'],
|
||||
defaultModalScroll: null,
|
||||
defaultDatepickerMobileNative: true,
|
||||
defaultTimepickerMobileNative: true,
|
||||
defaultNoticeQueue: true,
|
||||
defaultInputHasCounter: true,
|
||||
defaultUseHtml5Validation: true
|
||||
defaultUseHtml5Validation: true,
|
||||
defaultDropdownMobileModal: true,
|
||||
defaultFielLabelPosition: null,
|
||||
defaultDatepickerYearsRange: [-100, 3],
|
||||
defaultDatepickerNearbyMonthDays: true,
|
||||
defaultDatepickerNearbySelectableMonthDays: false
|
||||
}
|
||||
|
||||
export default config
|
||||
|
||||
Reference in New Issue
Block a user