This repository was archived by the owner on Mar 14, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 102
/
Copy pathcomponent.vue
160 lines (146 loc) · 4.35 KB
/
component.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
<template>
<input type="text" @input="onInput" data-input>
</template>
<script>
import Flatpickr from 'flatpickr';
// You have to import css yourself
import {includedEvents, excludedEvents} from "./events";
import {camelToKebab, cloneObject, arrayify} from "./util";
// Keep a copy of all events for later use
const allEvents = includedEvents.concat(excludedEvents);
// Passing these properties in `set()` method will cause flatpickr to trigger some callbacks
const configCallbacks = ['locale', 'showMonths'];
export default {
name: 'flat-pickr',
props: {
value: {
default: null,
required: true,
validator(value) {
return value === null || value instanceof Date || typeof value === 'string' || value instanceof String || value instanceof Array || typeof value === 'number'
}
},
// https://chmln.github.io/flatpickr/options/
config: {
type: Object,
default: () => ({
wrap: false,
defaultDate: null,
})
},
events: {
type: Array,
default: () => includedEvents
}
},
data() {
return {
/**
* The flatpickr instance
*/
fp: null,
};
},
mounted() {
// Return early if flatpickr is already loaded
/* istanbul ignore if */
if (this.fp) return;
// Don't mutate original object on parent component
let safeConfig = cloneObject(this.config);
// Inject our methods into events array
this.events.forEach((hook) => {
safeConfig[hook] = arrayify(safeConfig[hook] || []).concat((...args) => {
this.$emit(camelToKebab(hook), ...args)
});
});
// Set initial date without emitting any event
safeConfig.defaultDate = this.value || safeConfig.defaultDate;
// Init flatpickr
this.fp = new Flatpickr(this.getElem(), safeConfig);
// Attach blur event
this.fpInput().addEventListener('blur', this.onBlur)
},
methods: {
/**
* Get the HTML node where flatpickr to be attached
* Bind on parent element if wrap is true
*/
getElem() {
return this.config.wrap ? this.$el.parentNode : this.$el
},
/**
* Watch for value changed by date-picker itself and notify parent component
*
* @param event
*/
onInput(event) {
this.$emit('input', event.target.value);
},
/**
* @return HTMLElement
*/
fpInput() {
return this.fp.altInput || this.fp.input;
},
/**
* Blur event is required by many validation libraries
*
* @param event
*/
onBlur(event) {
this.$emit('blur', event.target.value);
}
},
watch: {
/**
* Watch for any config changes and redraw date-picker
*
* @param newConfig Object
*/
config: {
deep: true,
handler(newConfig) {
let safeConfig = cloneObject(newConfig);
// Workaround: Don't pass hooks to configs again otherwise
// previously registered hooks will stop working
// Notice: we are looping through all events
// This also means that new callbacks can not passed once component has been initialized
allEvents.forEach((hook) => {
delete safeConfig[hook];
});
this.fp.set(safeConfig);
// Workaround: Allow to change locale dynamically
configCallbacks.forEach((name) => {
if (typeof safeConfig[name] !== 'undefined') {
this.fp.set(name, safeConfig[name])
}
});
}
},
/**
* Watch for changes from parent component and update DOM
*
* @param newValue
*/
value(newValue) {
// Prevent updates if v-model value is same as input's current value
if (newValue === this.$el.value) return;
// Make sure we have a flatpickr instance
this.fp &&
// Notify flatpickr instance that there is a change in value
this.fp.setDate(newValue, true);
}
},
/**
* Free up memory
*/
beforeDestroy() {
/* istanbul ignore else */
if (this.fp) {
this.fpInput().removeEventListener('blur', this.onBlur);
this.fp.destroy();
this.fp = null;
}
},
};
</script>