v-calendar-3 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +9 -0
- package/README.md +142 -0
- package/dist/cjs/index.css +1133 -0
- package/dist/cjs/index.js +10699 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/es/index.js +10678 -0
- package/dist/es/index.js.map +1 -0
- package/dist/es/style.css +1134 -0
- package/dist/iife/index.js +2 -0
- package/dist/iife/index.js.map +1 -0
- package/dist/mjs/index.mjs +10678 -0
- package/dist/mjs/index.mjs.map +1 -0
- package/dist/mjs/style.css +1134 -0
- package/dist/style.css +1134 -0
- package/dist/types/components/BaseIcon/BaseIcon.vue.d.ts +41 -0
- package/dist/types/components/BaseIcon/icons/IconChevronDown.vue.d.ts +3 -0
- package/dist/types/components/BaseIcon/icons/IconChevronLeft.vue.d.ts +3 -0
- package/dist/types/components/BaseIcon/icons/IconChevronRight.vue.d.ts +3 -0
- package/dist/types/components/BaseIcon/icons/IconClock.vue.d.ts +3 -0
- package/dist/types/components/BaseIcon/icons/index.d.ts +4 -0
- package/dist/types/components/BaseSelect/BaseSelect.vue.d.ts +26 -0
- package/dist/types/components/Calendar/Calendar.vue.d.ts +2526 -0
- package/dist/types/components/Calendar/CalendarDay.vue.d.ts +83 -0
- package/dist/types/components/Calendar/CalendarDayPopover.vue.d.ts +3 -0
- package/dist/types/components/Calendar/CalendarHeader.vue.d.ts +13 -0
- package/dist/types/components/Calendar/CalendarNav.vue.d.ts +4 -0
- package/dist/types/components/Calendar/CalendarNavPopover.vue.d.ts +3 -0
- package/dist/types/components/Calendar/CalendarPage.vue.d.ts +3 -0
- package/dist/types/components/Calendar/CalendarPageProvider.vue.d.ts +17 -0
- package/dist/types/components/Calendar/CalendarSlot.vue.d.ts +15 -0
- package/dist/types/components/Calendar/CalendarTitleSelect.vue.d.ts +15 -0
- package/dist/types/components/CalendarGrid/CalendarCell.vue.d.ts +9 -0
- package/dist/types/components/CalendarGrid/CalendarCellPopover.vue.d.ts +209 -0
- package/dist/types/components/CalendarGrid/CalendarDayCell.vue.d.ts +8 -0
- package/dist/types/components/CalendarGrid/CalendarEventDetails.vue.d.ts +15 -0
- package/dist/types/components/CalendarGrid/CalendarEventEdit.vue.d.ts +26 -0
- package/dist/types/components/CalendarGrid/CalendarGrid.vue.d.ts +134 -0
- package/dist/types/components/CalendarGrid/CalendarGridWeek.vue.d.ts +8 -0
- package/dist/types/components/CalendarGrid/CalendarViewSelect.vue.d.ts +3 -0
- package/dist/types/components/CalendarGrid/CalendarWeekCell.vue.d.ts +10 -0
- package/dist/types/components/CalendarGrid/Constraints.d.ts +16 -0
- package/dist/types/components/DatePicker/DatePicker.vue.d.ts +15251 -0
- package/dist/types/components/DatePicker/DatePickerBase.vue.d.ts +3 -0
- package/dist/types/components/DatePicker/DatePickerPopover.vue.d.ts +3 -0
- package/dist/types/components/DatePicker/TimePicker.vue.d.ts +10089 -0
- package/dist/types/components/Popover/Popover.vue.d.ts +72 -0
- package/dist/types/components/Popover/PopoverRow.vue.d.ts +17 -0
- package/dist/types/components/index.d.ts +4 -0
- package/dist/types/index.d.cts +40981 -0
- package/dist/types/index.d.mts +40981 -0
- package/dist/types/index.d.ts +40981 -0
- package/dist/types/use/base.d.ts +67 -0
- package/dist/types/use/calendar.d.ts +2422 -0
- package/dist/types/use/calendarGrid.d.ts +9370 -0
- package/dist/types/use/datePicker.d.ts +20210 -0
- package/dist/types/use/page.d.ts +20 -0
- package/dist/types/use/slots.d.ts +5 -0
- package/dist/types/use/timePicker.d.ts +10089 -0
- package/dist/types/utils/attribute.d.ts +49 -0
- package/dist/types/utils/cache.d.ts +10 -0
- package/dist/types/utils/calendar/event.d.ts +111 -0
- package/dist/types/utils/config/index.d.ts +5 -0
- package/dist/types/utils/date/helpers.d.ts +161 -0
- package/dist/types/utils/date/range.d.ts +74 -0
- package/dist/types/utils/date/repeat.d.ts +34 -0
- package/dist/types/utils/date/rules.d.ts +82 -0
- package/dist/types/utils/defaults/index.d.ts +30 -0
- package/dist/types/utils/defaults/locales.d.ts +9 -0
- package/dist/types/utils/glyph.d.ts +58 -0
- package/dist/types/utils/helpers.d.ts +49 -0
- package/dist/types/utils/locale.d.ts +48 -0
- package/dist/types/utils/page.d.ts +95 -0
- package/dist/types/utils/plugins/index.d.ts +4 -0
- package/dist/types/utils/popovers.d.ts +47 -0
- package/dist/types/utils/theme.d.ts +17 -0
- package/dist/types/utils/touch.d.ts +8 -0
- package/dist/types/utils/useDisplayMode.d.ts +12 -0
- package/dist/types/utils/watchers.d.ts +6 -0
- package/package.json +115 -0
- package/src/components/BaseIcon/BaseIcon.vue +29 -0
- package/src/components/BaseIcon/icons/IconChevronDown.vue +5 -0
- package/src/components/BaseIcon/icons/IconChevronLeft.vue +5 -0
- package/src/components/BaseIcon/icons/IconChevronRight.vue +5 -0
- package/src/components/BaseIcon/icons/IconClock.vue +11 -0
- package/src/components/BaseIcon/icons/index.ts +4 -0
- package/src/components/BaseSelect/BaseSelect.vue +136 -0
- package/src/components/Calendar/Calendar.vue +116 -0
- package/src/components/Calendar/CalendarDay.vue +422 -0
- package/src/components/Calendar/CalendarDayPopover.vue +44 -0
- package/src/components/Calendar/CalendarHeader.vue +203 -0
- package/src/components/Calendar/CalendarNav.vue +325 -0
- package/src/components/Calendar/CalendarNavPopover.vue +24 -0
- package/src/components/Calendar/CalendarPage.vue +140 -0
- package/src/components/Calendar/CalendarPageProvider.vue +15 -0
- package/src/components/Calendar/CalendarSlot.vue +36 -0
- package/src/components/Calendar/CalendarTitleSelect.vue +72 -0
- package/src/components/CalendarGrid/CalendarCell.vue +112 -0
- package/src/components/CalendarGrid/CalendarCellPopover.vue +93 -0
- package/src/components/CalendarGrid/CalendarDayCell.vue +57 -0
- package/src/components/CalendarGrid/CalendarEventDetails.vue +71 -0
- package/src/components/CalendarGrid/CalendarEventEdit.vue +195 -0
- package/src/components/CalendarGrid/CalendarGrid.vue +715 -0
- package/src/components/CalendarGrid/CalendarGridWeek.vue +60 -0
- package/src/components/CalendarGrid/CalendarViewSelect.vue +34 -0
- package/src/components/CalendarGrid/CalendarWeekCell.vue +52 -0
- package/src/components/CalendarGrid/Constraints.ts +40 -0
- package/src/components/DatePicker/DatePicker.vue +27 -0
- package/src/components/DatePicker/DatePickerBase.vue +53 -0
- package/src/components/DatePicker/DatePickerPopover.vue +37 -0
- package/src/components/DatePicker/TimePicker.vue +167 -0
- package/src/components/Popover/Popover.vue +572 -0
- package/src/components/Popover/PopoverRow.vue +94 -0
- package/src/components/index.ts +4 -0
- package/src/index.ts +24 -0
- package/src/styles/index.css +48 -0
- package/src/styles/theme.css +322 -0
- package/src/styles/transitions.css +77 -0
- package/src/use/base.ts +144 -0
- package/src/use/calendar.ts +796 -0
- package/src/use/calendarGrid.ts +954 -0
- package/src/use/datePicker.ts +909 -0
- package/src/use/page.ts +78 -0
- package/src/use/slots.ts +17 -0
- package/src/use/timePicker.ts +194 -0
- package/src/utils/attribute.ts +107 -0
- package/src/utils/cache.ts +30 -0
- package/src/utils/calendar/event.ts +335 -0
- package/src/utils/config/index.ts +11 -0
- package/src/utils/date/helpers.ts +1039 -0
- package/src/utils/date/range.ts +274 -0
- package/src/utils/date/repeat.ts +135 -0
- package/src/utils/date/rules.ts +290 -0
- package/src/utils/defaults/index.ts +77 -0
- package/src/utils/defaults/locales.ts +123 -0
- package/src/utils/defaults/masks.json +15 -0
- package/src/utils/defaults/touch.json +5 -0
- package/src/utils/glyph.ts +305 -0
- package/src/utils/helpers.ts +181 -0
- package/src/utils/locale.ts +275 -0
- package/src/utils/page.ts +608 -0
- package/src/utils/plugins/index.ts +24 -0
- package/src/utils/popovers.ts +216 -0
- package/src/utils/theme.ts +58 -0
- package/src/utils/touch.ts +72 -0
- package/src/utils/useDisplayMode.ts +198 -0
- package/src/utils/watchers.ts +26 -0
|
@@ -0,0 +1,909 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type SetupContext,
|
|
3
|
+
type ExtractPropTypes,
|
|
4
|
+
type PropType,
|
|
5
|
+
ref,
|
|
6
|
+
computed,
|
|
7
|
+
watch,
|
|
8
|
+
onMounted,
|
|
9
|
+
onUnmounted,
|
|
10
|
+
nextTick,
|
|
11
|
+
toRef,
|
|
12
|
+
inject,
|
|
13
|
+
provide,
|
|
14
|
+
} from 'vue';
|
|
15
|
+
import Calendar from '../components/Calendar/Calendar.vue';
|
|
16
|
+
import Popover from '../components/Popover/Popover.vue';
|
|
17
|
+
import { getDefault } from '../utils/defaults';
|
|
18
|
+
import type { AttributeConfig } from '../utils/attribute';
|
|
19
|
+
import { type CalendarDay, getPageAddressForDate } from '../utils/page';
|
|
20
|
+
import {
|
|
21
|
+
defaultsDeep,
|
|
22
|
+
isArray,
|
|
23
|
+
isDate,
|
|
24
|
+
isNumber,
|
|
25
|
+
isObject,
|
|
26
|
+
isString,
|
|
27
|
+
} from '../utils/helpers';
|
|
28
|
+
import {
|
|
29
|
+
type DatePatch,
|
|
30
|
+
type DateParts,
|
|
31
|
+
type DatePartsRules,
|
|
32
|
+
type DateSource,
|
|
33
|
+
type SimpleDateParts,
|
|
34
|
+
isDateParts,
|
|
35
|
+
} from '../utils/date/helpers';
|
|
36
|
+
import type { SimpleDateRange } from '../utils/date/range';
|
|
37
|
+
import {
|
|
38
|
+
type PopoverOptions,
|
|
39
|
+
showPopover as sp,
|
|
40
|
+
hidePopover as hp,
|
|
41
|
+
togglePopover as tp,
|
|
42
|
+
getPopoverEventHandlers,
|
|
43
|
+
} from '../utils/popovers';
|
|
44
|
+
import { propsDef as basePropsDef, createBase } from './base';
|
|
45
|
+
import type { MoveTarget, MoveOptions } from './calendar';
|
|
46
|
+
import { provideSlots } from './slots';
|
|
47
|
+
|
|
48
|
+
export type DateType = 'date' | 'string' | 'number';
|
|
49
|
+
|
|
50
|
+
export interface DateConfig {
|
|
51
|
+
type: DateType;
|
|
52
|
+
rules: DatePartsRules;
|
|
53
|
+
mask?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const contextKey = Symbol('__vc_date_picker_context__');
|
|
57
|
+
|
|
58
|
+
export type DateModes = 'date' | 'datetime' | 'time';
|
|
59
|
+
|
|
60
|
+
export type ValueTarget = 'start' | 'end';
|
|
61
|
+
|
|
62
|
+
export interface UpdateOptions {
|
|
63
|
+
config: any;
|
|
64
|
+
patch: DatePatch;
|
|
65
|
+
debounce: number;
|
|
66
|
+
clearIfEqual: boolean;
|
|
67
|
+
formatInput: boolean;
|
|
68
|
+
hidePopover: boolean;
|
|
69
|
+
dragging: boolean;
|
|
70
|
+
targetPriority: ValueTarget;
|
|
71
|
+
moveToValue: boolean;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface ModelModifiers {
|
|
75
|
+
number?: boolean;
|
|
76
|
+
string?: boolean;
|
|
77
|
+
range?: boolean;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export type DatePickerDate = DateSource | Partial<SimpleDateParts> | null;
|
|
81
|
+
export type DatePickerRangeArray = [DatePickerDate, DatePickerDate];
|
|
82
|
+
export type DatePickerRangeObject = {
|
|
83
|
+
start: Exclude<DatePickerDate, null>;
|
|
84
|
+
end: Exclude<DatePickerDate, null>;
|
|
85
|
+
};
|
|
86
|
+
export type DatePickerModel = DatePickerDate | DatePickerRangeObject;
|
|
87
|
+
|
|
88
|
+
export type DatePickerContext = ReturnType<typeof createDatePicker>;
|
|
89
|
+
|
|
90
|
+
export type DatePickerProps = Readonly<ExtractPropTypes<typeof propsDef>>;
|
|
91
|
+
|
|
92
|
+
export const propsDef = {
|
|
93
|
+
...basePropsDef,
|
|
94
|
+
mode: { type: String, default: 'date' },
|
|
95
|
+
modelValue: {
|
|
96
|
+
type: [Number, String, Date, Object] as PropType<DatePickerModel>,
|
|
97
|
+
},
|
|
98
|
+
modelModifiers: {
|
|
99
|
+
type: Object as PropType<ModelModifiers>,
|
|
100
|
+
default: () => ({}),
|
|
101
|
+
},
|
|
102
|
+
rules: [String, Object] as PropType<'auto' | DatePartsRules>,
|
|
103
|
+
is24hr: Boolean,
|
|
104
|
+
hideTimeHeader: Boolean,
|
|
105
|
+
timeAccuracy: { type: Number, default: 2 },
|
|
106
|
+
isRequired: Boolean,
|
|
107
|
+
isRange: Boolean,
|
|
108
|
+
updateOnInput: {
|
|
109
|
+
type: Boolean,
|
|
110
|
+
default: () => getDefault('datePicker.updateOnInput'),
|
|
111
|
+
},
|
|
112
|
+
inputDebounce: {
|
|
113
|
+
type: Number,
|
|
114
|
+
default: () => getDefault('datePicker.inputDebounce'),
|
|
115
|
+
},
|
|
116
|
+
popover: {
|
|
117
|
+
type: [Boolean, Object] as PropType<boolean | Partial<PopoverOptions>>,
|
|
118
|
+
default: true,
|
|
119
|
+
},
|
|
120
|
+
dragAttribute: Object as PropType<AttributeConfig>,
|
|
121
|
+
selectAttribute: Object as PropType<AttributeConfig>,
|
|
122
|
+
attributes: [Object, Array],
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export const emits = [
|
|
126
|
+
'update:modelValue',
|
|
127
|
+
'drag',
|
|
128
|
+
'dayclick',
|
|
129
|
+
'daykeydown',
|
|
130
|
+
'popover-will-show',
|
|
131
|
+
'popover-did-show',
|
|
132
|
+
'popover-will-hide',
|
|
133
|
+
'popover-did-hide',
|
|
134
|
+
];
|
|
135
|
+
|
|
136
|
+
export function createDatePicker(
|
|
137
|
+
props: DatePickerProps,
|
|
138
|
+
{ emit, slots }: SetupContext<string[]>,
|
|
139
|
+
) {
|
|
140
|
+
provideSlots(slots, { footer: 'dp-footer' });
|
|
141
|
+
|
|
142
|
+
const baseCtx = createBase(props);
|
|
143
|
+
const { locale, masks, disabledAttribute } = baseCtx;
|
|
144
|
+
|
|
145
|
+
const showCalendar = ref(false);
|
|
146
|
+
const datePickerPopoverId = ref(Symbol());
|
|
147
|
+
const dateValue = ref<null | Date | SimpleDateRange>(null);
|
|
148
|
+
const dragValue = ref<null | SimpleDateRange>(null);
|
|
149
|
+
const inputValues = ref<string[]>(['', '']);
|
|
150
|
+
const popoverRef = ref<InstanceType<typeof Popover> | null>(null);
|
|
151
|
+
const calendarRef = ref<InstanceType<typeof Calendar> | null>(null);
|
|
152
|
+
|
|
153
|
+
let updateTimeout: ReturnType<typeof setTimeout> | undefined;
|
|
154
|
+
let dragTrackingValue: null | SimpleDateRange;
|
|
155
|
+
let watchValue = true;
|
|
156
|
+
|
|
157
|
+
// #region Computed
|
|
158
|
+
|
|
159
|
+
const isRange = computed(() => {
|
|
160
|
+
return props.isRange || props.modelModifiers.range === true;
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const valueStart = computed(() =>
|
|
164
|
+
isRange.value && dateValue.value != null
|
|
165
|
+
? (dateValue.value as SimpleDateRange).start
|
|
166
|
+
: null,
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
const valueEnd = computed(() =>
|
|
170
|
+
isRange.value && dateValue.value != null
|
|
171
|
+
? (dateValue.value as SimpleDateRange).end
|
|
172
|
+
: null,
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
const isDateMode = computed(() => props.mode.toLowerCase() === 'date');
|
|
176
|
+
const isDateTimeMode = computed(
|
|
177
|
+
() => props.mode.toLowerCase() === 'datetime',
|
|
178
|
+
);
|
|
179
|
+
const isTimeMode = computed(() => props.mode.toLowerCase() === 'time');
|
|
180
|
+
|
|
181
|
+
const isDragging = computed(() => !!dragValue.value);
|
|
182
|
+
|
|
183
|
+
const modelConfig = computed(() => {
|
|
184
|
+
let type: DateType = 'date';
|
|
185
|
+
if (props.modelModifiers.number) type = 'number';
|
|
186
|
+
if (props.modelModifiers.string) type = 'string';
|
|
187
|
+
const mask = masks.value.modelValue || 'iso';
|
|
188
|
+
return normalizeConfig(<DateConfig>{ type, mask });
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
const dateParts = computed(() =>
|
|
192
|
+
getDateParts(dragValue.value ?? dateValue.value),
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
const inputMask = computed(() => {
|
|
196
|
+
if (isTimeMode.value) {
|
|
197
|
+
return props.is24hr ? masks.value.inputTime24hr : masks.value.inputTime;
|
|
198
|
+
}
|
|
199
|
+
if (isDateTimeMode.value) {
|
|
200
|
+
return props.is24hr
|
|
201
|
+
? masks.value.inputDateTime24hr
|
|
202
|
+
: masks.value.inputDateTime;
|
|
203
|
+
}
|
|
204
|
+
return masks.value.input;
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
const inputMaskHasTime = computed(() => /[Hh]/g.test(inputMask.value));
|
|
208
|
+
|
|
209
|
+
const inputMaskHasDate = computed(() =>
|
|
210
|
+
/[dD]{1,2}|Do|W{1,4}|M{1,4}|YY(?:YY)?/g.test(inputMask.value),
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
const inputMaskPatch = computed(() => {
|
|
214
|
+
if (inputMaskHasTime.value && inputMaskHasDate.value) {
|
|
215
|
+
return 'dateTime';
|
|
216
|
+
}
|
|
217
|
+
if (inputMaskHasDate.value) return 'date';
|
|
218
|
+
if (inputMaskHasTime.value) return 'time';
|
|
219
|
+
return undefined;
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
const popover = computed(() => {
|
|
223
|
+
const target = popoverRef.value?.$el.previousElementSibling ?? undefined;
|
|
224
|
+
return defaultsDeep({}, props.popover, getDefault('datePicker.popover'), {
|
|
225
|
+
target,
|
|
226
|
+
}) as Partial<PopoverOptions>;
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
const popoverEvents = computed(() =>
|
|
230
|
+
getPopoverEventHandlers({
|
|
231
|
+
...popover.value,
|
|
232
|
+
id: datePickerPopoverId.value,
|
|
233
|
+
}),
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
const inputValue = computed(() => {
|
|
237
|
+
return isRange.value
|
|
238
|
+
? {
|
|
239
|
+
start: inputValues.value[0],
|
|
240
|
+
end: inputValues.value[1],
|
|
241
|
+
}
|
|
242
|
+
: inputValues.value[0];
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
const inputEvents = computed(() => {
|
|
246
|
+
const events = (['start', 'end'] as const).map(target => ({
|
|
247
|
+
input: onInputInput(target),
|
|
248
|
+
change: onInputChange(target),
|
|
249
|
+
keyup: onInputKeyup,
|
|
250
|
+
...(props.popover && popoverEvents.value),
|
|
251
|
+
}));
|
|
252
|
+
return isRange.value
|
|
253
|
+
? {
|
|
254
|
+
start: events[0],
|
|
255
|
+
end: events[1],
|
|
256
|
+
}
|
|
257
|
+
: events[0];
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
const selectAttribute = computed(() => {
|
|
261
|
+
if (!hasValue(dateValue.value)) return null;
|
|
262
|
+
const attribute = {
|
|
263
|
+
key: 'select-drag',
|
|
264
|
+
...props.selectAttribute,
|
|
265
|
+
dates: dateValue.value,
|
|
266
|
+
pinPage: true,
|
|
267
|
+
};
|
|
268
|
+
const { dot, bar, highlight, content } = attribute;
|
|
269
|
+
if (!dot && !bar && !highlight && !content) {
|
|
270
|
+
attribute.highlight = true;
|
|
271
|
+
}
|
|
272
|
+
return attribute;
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
const dragAttribute = computed(() => {
|
|
276
|
+
if (!isRange.value || !hasValue(dragValue.value)) {
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
const attribute = {
|
|
280
|
+
key: 'select-drag',
|
|
281
|
+
...props.dragAttribute,
|
|
282
|
+
dates: dragValue.value,
|
|
283
|
+
};
|
|
284
|
+
const { dot, bar, highlight, content } = attribute;
|
|
285
|
+
if (!dot && !bar && !highlight && !content) {
|
|
286
|
+
attribute.highlight = {
|
|
287
|
+
startEnd: {
|
|
288
|
+
fillMode: 'outline',
|
|
289
|
+
},
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
return attribute;
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
const attributes = computed(() => {
|
|
296
|
+
const attrs = isArray(props.attributes) ? [...props.attributes] : [];
|
|
297
|
+
if (dragAttribute.value) {
|
|
298
|
+
attrs.unshift(dragAttribute.value);
|
|
299
|
+
} else if (selectAttribute.value) {
|
|
300
|
+
attrs.unshift(selectAttribute.value);
|
|
301
|
+
}
|
|
302
|
+
return attrs;
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
const rules = computed(() => {
|
|
306
|
+
return normalizeConfig(
|
|
307
|
+
props.rules === 'auto' ? getAutoRules() : (props.rules ?? {}),
|
|
308
|
+
);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// #endregion Computed
|
|
312
|
+
|
|
313
|
+
function getAutoRules() {
|
|
314
|
+
const _rules = {
|
|
315
|
+
ms: [0, 999],
|
|
316
|
+
sec: [0, 59],
|
|
317
|
+
min: [0, 59],
|
|
318
|
+
hr: [0, 23],
|
|
319
|
+
};
|
|
320
|
+
const accuracy = isDateMode.value ? 0 : props.timeAccuracy;
|
|
321
|
+
return [0, 1].map(i => {
|
|
322
|
+
switch (accuracy) {
|
|
323
|
+
case 0:
|
|
324
|
+
return {
|
|
325
|
+
hours: _rules.hr[i],
|
|
326
|
+
minutes: _rules.min[i],
|
|
327
|
+
seconds: _rules.sec[i],
|
|
328
|
+
milliseconds: _rules.ms[i],
|
|
329
|
+
};
|
|
330
|
+
case 1:
|
|
331
|
+
return {
|
|
332
|
+
minutes: _rules.min[i],
|
|
333
|
+
seconds: _rules.sec[i],
|
|
334
|
+
milliseconds: _rules.ms[i],
|
|
335
|
+
};
|
|
336
|
+
case 3:
|
|
337
|
+
return { milliseconds: _rules.ms[i] };
|
|
338
|
+
case 4:
|
|
339
|
+
return {};
|
|
340
|
+
default:
|
|
341
|
+
return { seconds: _rules.sec[i], milliseconds: _rules.ms[i] };
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function normalizeConfig<T>(config: T | T[]): T[] {
|
|
347
|
+
if (isArray(config)) {
|
|
348
|
+
if (config.length === 1) return [config[0], config[0]];
|
|
349
|
+
return config;
|
|
350
|
+
}
|
|
351
|
+
return [config, config];
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function normalizeDateConfig(
|
|
355
|
+
config: Partial<DateConfig> | Partial<DateConfig>[],
|
|
356
|
+
): DateConfig[] {
|
|
357
|
+
return normalizeConfig(config).map(
|
|
358
|
+
(c, i) =>
|
|
359
|
+
({
|
|
360
|
+
...c,
|
|
361
|
+
rules: rules.value[i],
|
|
362
|
+
}) as DateConfig,
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function hasDateValue(
|
|
367
|
+
value: DatePickerDate,
|
|
368
|
+
): value is Exclude<DatePickerDate, null> {
|
|
369
|
+
if (value == null) return false;
|
|
370
|
+
if (isNumber(value)) return !isNaN(value);
|
|
371
|
+
if (isDate(value)) return !isNaN(value.getTime());
|
|
372
|
+
if (isString(value)) return value !== '';
|
|
373
|
+
return isDateParts(value);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function hasRangeValue(value: unknown): value is DatePickerRangeObject {
|
|
377
|
+
return (
|
|
378
|
+
isObject(value) &&
|
|
379
|
+
'start' in value &&
|
|
380
|
+
'end' in value &&
|
|
381
|
+
hasDateValue(value.start ?? null) &&
|
|
382
|
+
hasDateValue(value.end ?? null)
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function hasValue(
|
|
387
|
+
value: DatePickerModel,
|
|
388
|
+
): value is Exclude<DatePickerDate, null> | DatePickerRangeObject {
|
|
389
|
+
return hasRangeValue(value) || hasDateValue(value);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function valuesAreEqual(
|
|
393
|
+
a: null | Date | SimpleDateRange,
|
|
394
|
+
b: null | Date | SimpleDateRange,
|
|
395
|
+
): boolean {
|
|
396
|
+
if (a == null && b == null) return true;
|
|
397
|
+
if (a == null || b == null) return false;
|
|
398
|
+
const aIsDate = isDate(a);
|
|
399
|
+
const bIsDate = isDate(b);
|
|
400
|
+
if (aIsDate && bIsDate) return a.getTime() === b.getTime();
|
|
401
|
+
if (aIsDate || bIsDate) return false;
|
|
402
|
+
return valuesAreEqual(a.start, b.start) && valuesAreEqual(a.end, b.end);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function valueIsDisabled(value: Date | SimpleDateRange | null) {
|
|
406
|
+
if (!hasValue(value) || !disabledAttribute.value) return false;
|
|
407
|
+
return disabledAttribute.value.intersectsRange(locale.value.range(value));
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function normalizeValue(
|
|
411
|
+
value: DatePickerModel,
|
|
412
|
+
config: DateConfig[],
|
|
413
|
+
patch: DatePatch,
|
|
414
|
+
targetPriority?: ValueTarget,
|
|
415
|
+
): Date | SimpleDateRange | null {
|
|
416
|
+
if (!hasValue(value)) return null;
|
|
417
|
+
if (hasRangeValue(value)) {
|
|
418
|
+
const start = locale.value.toDate(value.start, {
|
|
419
|
+
...config[0],
|
|
420
|
+
fillDate: valueStart.value ?? undefined,
|
|
421
|
+
patch,
|
|
422
|
+
});
|
|
423
|
+
const end = locale.value.toDate(value.end, {
|
|
424
|
+
...config[1],
|
|
425
|
+
fillDate: valueEnd.value ?? undefined,
|
|
426
|
+
patch,
|
|
427
|
+
});
|
|
428
|
+
return sortRange({ start, end }, targetPriority);
|
|
429
|
+
}
|
|
430
|
+
return locale.value.toDateOrNull(value, {
|
|
431
|
+
...config[0],
|
|
432
|
+
fillDate: dateValue.value as Date,
|
|
433
|
+
patch,
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function denormalizeValue(
|
|
438
|
+
value: null | Date | SimpleDateRange,
|
|
439
|
+
config: DateConfig[],
|
|
440
|
+
) {
|
|
441
|
+
if (hasRangeValue(value)) {
|
|
442
|
+
return {
|
|
443
|
+
start: locale.value.fromDate(value.start, config[0]),
|
|
444
|
+
end: locale.value.fromDate(value.end, config[1]),
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
if (isRange.value) {
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
450
|
+
return locale.value.fromDate(value, config[0]);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function updateValue(
|
|
454
|
+
value: any,
|
|
455
|
+
opts: Partial<UpdateOptions> = {},
|
|
456
|
+
): Promise<ReturnType<typeof forceUpdateValue>> {
|
|
457
|
+
clearTimeout(updateTimeout);
|
|
458
|
+
return new Promise(resolve => {
|
|
459
|
+
const { debounce = 0, ...args } = opts;
|
|
460
|
+
if (debounce > 0) {
|
|
461
|
+
updateTimeout = setTimeout(() => {
|
|
462
|
+
resolve(forceUpdateValue(value, args));
|
|
463
|
+
}, debounce);
|
|
464
|
+
} else {
|
|
465
|
+
resolve(forceUpdateValue(value, args));
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function forceUpdateValue(
|
|
471
|
+
value: any,
|
|
472
|
+
{
|
|
473
|
+
config = modelConfig.value,
|
|
474
|
+
patch = 'dateTime',
|
|
475
|
+
clearIfEqual = false,
|
|
476
|
+
formatInput: fInput = true,
|
|
477
|
+
hidePopover: hPopover = false,
|
|
478
|
+
dragging = isDragging.value,
|
|
479
|
+
targetPriority,
|
|
480
|
+
moveToValue: mValue = false,
|
|
481
|
+
}: Partial<UpdateOptions> = {},
|
|
482
|
+
) {
|
|
483
|
+
// 1. Normalization
|
|
484
|
+
const normalizedConfig = normalizeDateConfig(config);
|
|
485
|
+
let normalizedValue = normalizeValue(
|
|
486
|
+
value,
|
|
487
|
+
normalizedConfig,
|
|
488
|
+
patch,
|
|
489
|
+
targetPriority,
|
|
490
|
+
);
|
|
491
|
+
|
|
492
|
+
// 2a. Validation against disabled dates
|
|
493
|
+
const isDisabled = valueIsDisabled(normalizedValue);
|
|
494
|
+
if (isDisabled) {
|
|
495
|
+
if (dragging) return null;
|
|
496
|
+
normalizedValue = dateValue.value;
|
|
497
|
+
// Don't allow hiding popover
|
|
498
|
+
hPopover = false;
|
|
499
|
+
// 2b. Validation against is-required or clearIfEqual
|
|
500
|
+
} else if (normalizedValue == null && props.isRequired) {
|
|
501
|
+
// Reset to previous value if it was cleared but is required
|
|
502
|
+
normalizedValue = dateValue.value;
|
|
503
|
+
// 2c. Validation against clearIfEqual
|
|
504
|
+
} else if (
|
|
505
|
+
// Clear value if same value was passed
|
|
506
|
+
normalizedValue != null &&
|
|
507
|
+
valuesAreEqual(dateValue.value, normalizedValue) &&
|
|
508
|
+
clearIfEqual
|
|
509
|
+
) {
|
|
510
|
+
normalizedValue = null;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// 3. Assignment
|
|
514
|
+
const valueRef = dragging ? dragValue : dateValue;
|
|
515
|
+
const notify = !valuesAreEqual(valueRef.value, normalizedValue);
|
|
516
|
+
valueRef.value = normalizedValue;
|
|
517
|
+
// Clear drag value if needed
|
|
518
|
+
if (!dragging) dragValue.value = null;
|
|
519
|
+
// Denormalize value using the model config
|
|
520
|
+
const denormalizedValue = denormalizeValue(
|
|
521
|
+
normalizedValue,
|
|
522
|
+
modelConfig.value,
|
|
523
|
+
);
|
|
524
|
+
|
|
525
|
+
// 4. Notification
|
|
526
|
+
if (notify) {
|
|
527
|
+
watchValue = false;
|
|
528
|
+
emit(dragging ? 'drag' : 'update:modelValue', denormalizedValue);
|
|
529
|
+
nextTick(() => (watchValue = true));
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// 5. Hide popover if needed
|
|
533
|
+
if (hPopover && !dragging) hidePopover();
|
|
534
|
+
|
|
535
|
+
// 6. Format inputs if needed
|
|
536
|
+
if (fInput) formatInput();
|
|
537
|
+
|
|
538
|
+
// 7. Move to range target if needed
|
|
539
|
+
if (mValue) {
|
|
540
|
+
nextTick(() => moveToValue(targetPriority ?? 'start'));
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
return denormalizedValue;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function formatInput() {
|
|
547
|
+
nextTick(() => {
|
|
548
|
+
const config = normalizeDateConfig({
|
|
549
|
+
type: 'string',
|
|
550
|
+
mask: inputMask.value,
|
|
551
|
+
});
|
|
552
|
+
const value = denormalizeValue(
|
|
553
|
+
dragValue.value ?? dateValue.value,
|
|
554
|
+
config,
|
|
555
|
+
);
|
|
556
|
+
if (isRange.value) {
|
|
557
|
+
// @ts-ignore
|
|
558
|
+
inputValues.value = [value && value.start, value && value.end];
|
|
559
|
+
} else {
|
|
560
|
+
inputValues.value = [value as string, ''];
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
function onInputUpdate(
|
|
566
|
+
inputValue: string,
|
|
567
|
+
target: ValueTarget,
|
|
568
|
+
opts: Partial<UpdateOptions>,
|
|
569
|
+
) {
|
|
570
|
+
inputValues.value.splice(target === 'start' ? 0 : 1, 1, inputValue);
|
|
571
|
+
const value = isRange.value
|
|
572
|
+
? {
|
|
573
|
+
start: inputValues.value[0],
|
|
574
|
+
end: inputValues.value[1] || inputValues.value[0],
|
|
575
|
+
}
|
|
576
|
+
: inputValue;
|
|
577
|
+
const config = {
|
|
578
|
+
type: 'string',
|
|
579
|
+
mask: inputMask.value,
|
|
580
|
+
};
|
|
581
|
+
updateValue(value, {
|
|
582
|
+
...opts,
|
|
583
|
+
config,
|
|
584
|
+
patch: inputMaskPatch.value,
|
|
585
|
+
targetPriority: target,
|
|
586
|
+
moveToValue: true,
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
function onInputInput(target: ValueTarget) {
|
|
591
|
+
return (e: InputEvent) => {
|
|
592
|
+
if (!props.updateOnInput) return;
|
|
593
|
+
onInputUpdate((<HTMLInputElement>e.currentTarget).value, target, {
|
|
594
|
+
formatInput: false,
|
|
595
|
+
hidePopover: false,
|
|
596
|
+
debounce: props.inputDebounce,
|
|
597
|
+
});
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
function onInputChange(target: ValueTarget) {
|
|
602
|
+
return (e: InputEvent) => {
|
|
603
|
+
onInputUpdate((<HTMLInputElement>e.currentTarget).value, target, {
|
|
604
|
+
formatInput: true,
|
|
605
|
+
hidePopover: false,
|
|
606
|
+
});
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
function onInputKeyup(e: KeyboardEvent) {
|
|
611
|
+
// Escape key only
|
|
612
|
+
if (e.key !== 'Escape') return;
|
|
613
|
+
updateValue(dateValue.value, {
|
|
614
|
+
formatInput: true,
|
|
615
|
+
hidePopover: true,
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
function getDateParts(value: any): (DateParts | null)[] {
|
|
620
|
+
if (isRange.value) {
|
|
621
|
+
return [
|
|
622
|
+
value && value.start ? locale.value.getDateParts(value.start) : null,
|
|
623
|
+
value && value.end ? locale.value.getDateParts(value.end) : null,
|
|
624
|
+
];
|
|
625
|
+
}
|
|
626
|
+
return [value ? locale.value.getDateParts(value) : null];
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
function cancelDrag() {
|
|
630
|
+
dragValue.value = null;
|
|
631
|
+
formatInput();
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
function onPopoverBeforeShow(el: HTMLElement) {
|
|
635
|
+
emit('popover-will-show', el);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
function onPopoverAfterShow(el: HTMLElement) {
|
|
639
|
+
emit('popover-did-show', el);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
function onPopoverBeforeHide(el: HTMLElement) {
|
|
643
|
+
cancelDrag();
|
|
644
|
+
emit('popover-will-hide', el);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
function onPopoverAfterHide(el: HTMLElement) {
|
|
648
|
+
emit('popover-did-hide', el);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
function handleDayClick(day: CalendarDay) {
|
|
652
|
+
const opts: Partial<UpdateOptions> = {
|
|
653
|
+
patch: 'date',
|
|
654
|
+
formatInput: true,
|
|
655
|
+
hidePopover: true,
|
|
656
|
+
};
|
|
657
|
+
if (isRange.value) {
|
|
658
|
+
const dragging = !isDragging.value;
|
|
659
|
+
if (dragging) {
|
|
660
|
+
dragTrackingValue = { start: day.startDate, end: day.endDate };
|
|
661
|
+
} else if (dragTrackingValue != null) {
|
|
662
|
+
dragTrackingValue.end = day.date;
|
|
663
|
+
}
|
|
664
|
+
updateValue(dragTrackingValue, {
|
|
665
|
+
...opts,
|
|
666
|
+
dragging,
|
|
667
|
+
});
|
|
668
|
+
} else {
|
|
669
|
+
updateValue(day.date, {
|
|
670
|
+
...opts,
|
|
671
|
+
clearIfEqual: !props.isRequired,
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
function onDayClick(day: CalendarDay, event: MouseEvent) {
|
|
677
|
+
handleDayClick(day);
|
|
678
|
+
// Re-emit event
|
|
679
|
+
emit('dayclick', day, event);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
function onDayKeydown(day: CalendarDay, event: KeyboardEvent) {
|
|
683
|
+
switch (event.key) {
|
|
684
|
+
case ' ':
|
|
685
|
+
case 'Enter': {
|
|
686
|
+
handleDayClick(day);
|
|
687
|
+
event.preventDefault();
|
|
688
|
+
break;
|
|
689
|
+
}
|
|
690
|
+
case 'Escape': {
|
|
691
|
+
hidePopover();
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
// Re-emit event
|
|
695
|
+
emit('daykeydown', day, event);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
function onDayMouseEnter(day: CalendarDay, event: MouseEvent) {
|
|
699
|
+
if (!isDragging.value || dragTrackingValue == null) return;
|
|
700
|
+
dragTrackingValue.end = day.date;
|
|
701
|
+
updateValue(sortRange(dragTrackingValue), {
|
|
702
|
+
patch: 'date',
|
|
703
|
+
formatInput: true,
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
function showPopover(opts: Partial<PopoverOptions> = {}) {
|
|
708
|
+
sp({
|
|
709
|
+
...popover.value,
|
|
710
|
+
...opts,
|
|
711
|
+
isInteractive: true,
|
|
712
|
+
id: datePickerPopoverId.value,
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
function hidePopover(opts: Partial<PopoverOptions> = {}) {
|
|
717
|
+
hp({
|
|
718
|
+
hideDelay: 10,
|
|
719
|
+
force: true,
|
|
720
|
+
...popover.value,
|
|
721
|
+
...opts,
|
|
722
|
+
id: datePickerPopoverId.value,
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
function togglePopover(opts: Partial<PopoverOptions>) {
|
|
727
|
+
tp({
|
|
728
|
+
...popover.value,
|
|
729
|
+
...opts,
|
|
730
|
+
isInteractive: true,
|
|
731
|
+
id: datePickerPopoverId.value,
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
function sortRange(range: SimpleDateRange, priority?: ValueTarget) {
|
|
736
|
+
const { start, end } = range;
|
|
737
|
+
if (start > end) {
|
|
738
|
+
switch (priority) {
|
|
739
|
+
case 'start':
|
|
740
|
+
return { start, end: start };
|
|
741
|
+
case 'end':
|
|
742
|
+
return { start: end, end };
|
|
743
|
+
default:
|
|
744
|
+
return { start: end, end: start };
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
return { start, end };
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
async function move(target: MoveTarget, opts: Partial<MoveOptions> = {}) {
|
|
751
|
+
if (calendarRef.value == null) return false;
|
|
752
|
+
return calendarRef.value.move(target, opts);
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
async function moveBy(pages: number, opts: Partial<MoveOptions> = {}) {
|
|
756
|
+
if (calendarRef.value == null) return false;
|
|
757
|
+
return calendarRef.value.moveBy(pages, opts);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
async function moveToValue(
|
|
761
|
+
target: ValueTarget,
|
|
762
|
+
opts: Partial<MoveOptions> = {},
|
|
763
|
+
) {
|
|
764
|
+
const dValue = dateValue.value;
|
|
765
|
+
if (calendarRef.value == null || !hasValue(dValue)) return false;
|
|
766
|
+
const start = target !== 'end';
|
|
767
|
+
const position = start ? 1 : -1;
|
|
768
|
+
const date = hasRangeValue(dValue)
|
|
769
|
+
? start
|
|
770
|
+
? dValue.start
|
|
771
|
+
: dValue.end
|
|
772
|
+
: dValue;
|
|
773
|
+
const page = getPageAddressForDate(date, 'monthly', locale.value);
|
|
774
|
+
return calendarRef.value.move(page, { position, ...opts });
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
// #endregion Methods
|
|
778
|
+
|
|
779
|
+
// #region Watch
|
|
780
|
+
|
|
781
|
+
watch(
|
|
782
|
+
() => props.isRange,
|
|
783
|
+
val => {
|
|
784
|
+
if (val) {
|
|
785
|
+
console.warn(
|
|
786
|
+
'The `is-range` prop will be deprecated in future releases. Please use the `range` modifier.',
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
},
|
|
790
|
+
{ immediate: true },
|
|
791
|
+
);
|
|
792
|
+
|
|
793
|
+
watch(
|
|
794
|
+
() => isRange.value,
|
|
795
|
+
() => {
|
|
796
|
+
forceUpdateValue(null, { formatInput: true });
|
|
797
|
+
},
|
|
798
|
+
);
|
|
799
|
+
|
|
800
|
+
watch(
|
|
801
|
+
() => inputMask.value,
|
|
802
|
+
() => formatInput(),
|
|
803
|
+
);
|
|
804
|
+
|
|
805
|
+
watch(
|
|
806
|
+
() => props.modelValue,
|
|
807
|
+
val => {
|
|
808
|
+
if (!watchValue) return;
|
|
809
|
+
forceUpdateValue(val, {
|
|
810
|
+
formatInput: true,
|
|
811
|
+
hidePopover: false,
|
|
812
|
+
});
|
|
813
|
+
},
|
|
814
|
+
);
|
|
815
|
+
|
|
816
|
+
watch(
|
|
817
|
+
() => rules.value,
|
|
818
|
+
() => {
|
|
819
|
+
if (isObject(props.rules)) {
|
|
820
|
+
forceUpdateValue(props.modelValue, {
|
|
821
|
+
formatInput: true,
|
|
822
|
+
hidePopover: false,
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
},
|
|
826
|
+
);
|
|
827
|
+
|
|
828
|
+
watch(
|
|
829
|
+
() => props.timezone,
|
|
830
|
+
() => {
|
|
831
|
+
forceUpdateValue(dateValue.value, { formatInput: true });
|
|
832
|
+
},
|
|
833
|
+
);
|
|
834
|
+
|
|
835
|
+
// #endregion Watch
|
|
836
|
+
|
|
837
|
+
// #region Lifecycle
|
|
838
|
+
|
|
839
|
+
// Set initial date value (no validation applied)
|
|
840
|
+
const config = normalizeConfig(modelConfig.value);
|
|
841
|
+
dateValue.value = normalizeValue(
|
|
842
|
+
props.modelValue ?? null,
|
|
843
|
+
config,
|
|
844
|
+
'dateTime',
|
|
845
|
+
);
|
|
846
|
+
|
|
847
|
+
onMounted(() => {
|
|
848
|
+
forceUpdateValue(props.modelValue, {
|
|
849
|
+
formatInput: true,
|
|
850
|
+
hidePopover: false,
|
|
851
|
+
});
|
|
852
|
+
});
|
|
853
|
+
|
|
854
|
+
onUnmounted(() => {
|
|
855
|
+
clearTimeout(updateTimeout);
|
|
856
|
+
hidePopover({ hideDelay: 0 });
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
// Created
|
|
860
|
+
// Waiting a tick allows calendar to initialize page
|
|
861
|
+
nextTick(() => (showCalendar.value = true));
|
|
862
|
+
|
|
863
|
+
// #endregion Lifecycle
|
|
864
|
+
|
|
865
|
+
const context = {
|
|
866
|
+
...baseCtx,
|
|
867
|
+
showCalendar,
|
|
868
|
+
datePickerPopoverId,
|
|
869
|
+
popoverRef,
|
|
870
|
+
popoverEvents,
|
|
871
|
+
calendarRef,
|
|
872
|
+
isRange,
|
|
873
|
+
isTimeMode,
|
|
874
|
+
isDateTimeMode,
|
|
875
|
+
is24hr: toRef(props, 'is24hr'),
|
|
876
|
+
hideTimeHeader: toRef(props, 'hideTimeHeader'),
|
|
877
|
+
timeAccuracy: toRef(props, 'timeAccuracy'),
|
|
878
|
+
isDragging,
|
|
879
|
+
inputValue,
|
|
880
|
+
inputEvents,
|
|
881
|
+
dateParts,
|
|
882
|
+
attributes,
|
|
883
|
+
rules,
|
|
884
|
+
move,
|
|
885
|
+
moveBy,
|
|
886
|
+
moveToValue,
|
|
887
|
+
updateValue,
|
|
888
|
+
showPopover,
|
|
889
|
+
hidePopover,
|
|
890
|
+
togglePopover,
|
|
891
|
+
onDayClick,
|
|
892
|
+
onDayKeydown,
|
|
893
|
+
onDayMouseEnter,
|
|
894
|
+
onPopoverBeforeShow,
|
|
895
|
+
onPopoverAfterShow,
|
|
896
|
+
onPopoverBeforeHide,
|
|
897
|
+
onPopoverAfterHide,
|
|
898
|
+
};
|
|
899
|
+
provide(contextKey, context);
|
|
900
|
+
return context;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
export function useDatePicker() {
|
|
904
|
+
const context = inject<DatePickerContext>(contextKey);
|
|
905
|
+
if (context) return context;
|
|
906
|
+
throw new Error(
|
|
907
|
+
'DatePicker context missing. Please verify this component is nested within a valid context provider.',
|
|
908
|
+
);
|
|
909
|
+
}
|