Skip to content
This repository was archived by the owner on Apr 17, 2022. It is now read-only.

Commit 2e02b11

Browse files
committed
feat: Add option to select and jump (resolves #87)
1 parent 487ba29 commit 2e02b11

File tree

10 files changed

+186
-19
lines changed

10 files changed

+186
-19
lines changed

index.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ type EmitEvents =
1111
| 'focus'
1212
| 'blur'
1313
| 'internalModelChange'
14-
| 'recalculatePosition';
14+
| 'recalculatePosition'
15+
| 'flow-step';
1516

1617
interface Vue3DatePicker {
1718
uid?: string;
@@ -181,6 +182,7 @@ interface Vue3DatePicker {
181182
autocomplete?: string;
182183
multiDates?: boolean;
183184
presetRanges?: { label: string; range: Date[] | string[] }[];
185+
flow: ('month' | 'year' | 'calendar' | 'time' | 'minutes' | 'hours' | 'seconds')[];
184186
}
185187

186188
interface PublicMethods extends MethodOptions {

src/Vue3DatePicker/Vue3DatePicker.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,15 @@
107107
readonly,
108108
multiDates,
109109
presetRanges,
110+
flow,
110111
}"
111112
v-model:internalModelValue="internalModelValue"
112113
@close-picker="closeMenu"
113114
@select-date="selectDate"
114115
@dp-open="recalculatePosition"
115116
@auto-apply="autoApplyValue"
116117
@time-update="timeUpdate"
118+
@flow-step="$emit('flow-step', $event)"
117119
>
118120
<template v-for="(slot, i) in slotList" #[slot]="args" :key="i">
119121
<slot :name="slot" v-bind="{ ...args }" />
@@ -156,6 +158,7 @@
156158
IDisableDates,
157159
AltPosition,
158160
PresetRange,
161+
Flow,
159162
} from './interfaces';
160163
import { getDefaultPattern, isValidTime } from './utils/date-utils';
161164
import { getDefaultTextInputOptions, getDefaultFilters, mergeDefaultTransitions } from './utils/util';
@@ -175,6 +178,7 @@
175178
'blur',
176179
'internalModelChange',
177180
'recalculatePosition',
181+
'flow-step',
178182
]);
179183
const props = defineProps({
180184
uid: { type: String as PropType<string>, default: null },
@@ -269,6 +273,7 @@
269273
autocomplete: { type: String as PropType<string>, default: null },
270274
multiDates: { type: Boolean as PropType<boolean>, default: false },
271275
presetRanges: { type: Array as PropType<PresetRange[]>, default: () => [] },
276+
flow: { type: Array as PropType<Flow>, default: () => [] },
272277
});
273278
const slots = useSlots();
274279
const isOpen = ref(false);

src/Vue3DatePicker/components/Calendar.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@
122122
import { getDayNames, getDefaultMarker, unrefElement } from '../utils/util';
123123
import { isDateAfter, isDateEqual, setDateMonthOrYear } from '../utils/date-utils';
124124
125-
const emit = defineEmits(['selectDate', 'setHoverDate', 'handleScroll']);
125+
const emit = defineEmits(['selectDate', 'setHoverDate', 'handleScroll', 'mount']);
126126
127127
const props = defineProps({
128128
locale: { type: String as PropType<string>, default: 'en-Us' },
@@ -173,6 +173,7 @@
173173
startTransitions.value = true;
174174
}
175175
prevDate.value = setDateMonthOrYear(new Date(), props.month, props.year);
176+
emit('mount');
176177
});
177178
178179
const specificMode = computed(() => props.monthPicker || props.timePicker);

src/Vue3DatePicker/components/DatepickerMenu.vue

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,14 @@
2828
</div>
2929
<div class="dp__instance_calendar" ref="calendarWrapperRef" role="document">
3030
<div :class="menuCalendarClassWrapper">
31-
<div v-for="instance in calendarAmm" :key="instance" :class="calendarInstanceClassWrapper">
31+
<div v-for="(instance, i) in calendarAmm" :key="instance" :class="calendarInstanceClassWrapper">
3232
<component
3333
:is="monthYearComponent ? monthYearComponent : MonthYearInput"
34+
:ref="
35+
(el) => {
36+
if (el) monthYearInputRefs[i] = el;
37+
}
38+
"
3439
v-if="!disableMonthYearSelect && !timePicker"
3540
v-bind="{
3641
months,
@@ -46,6 +51,8 @@
4651
minDate,
4752
maxDate,
4853
}"
54+
@mount="childMount('monthYearInput')"
55+
@reset-flow="resetFlow"
4956
@update:month="updateMonthYear(instance, $event, true)"
5057
@update:year="updateMonthYear(instance, $event, false)"
5158
@month-year-select="monthYearSelect"
@@ -56,6 +63,7 @@
5663
</component>
5764
<Calendar
5865
v-bind="calendarProps"
66+
v-model:flow-step="flowStep"
5967
:instance="instance"
6068
:mapped-dates="mappedDates(instance)"
6169
:month="month(instance)"
@@ -64,6 +72,8 @@
6472
@select-date="selectDate($event, !isFirstInstance(instance))"
6573
@set-hover-date="setHoverDate($event)"
6674
@handle-scroll="handleScroll($event, instance)"
75+
@mount="childMount('calendar')"
76+
@reset-flow="resetFlow"
6777
>
6878
<template v-for="(slot, i) in calendarSlots" #[slot]="args" :key="i">
6979
<slot :name="slot" v-bind="{ ...args }" />
@@ -96,9 +106,11 @@
96106
customProps,
97107
enableSeconds,
98108
}"
109+
@mount="childMount('timePicker')"
99110
@update:hours="updateTime($event)"
100111
@update:minutes="updateTime($event, false)"
101112
@update:seconds="updateTime($event, false, true)"
113+
@reset-flow="resetFlow"
102114
>
103115
<template v-for="(slot, i) in timePickerSlots" #[slot]="args" :key="i">
104116
<slot :name="slot" v-bind="args" />
@@ -163,6 +175,7 @@
163175
ComputedRef,
164176
ref,
165177
onUnmounted,
178+
reactive,
166179
} from 'vue';
167180
import Calendar from './Calendar.vue';
168181
import ActionRow from './ActionRow.vue';
@@ -171,6 +184,7 @@
171184
172185
import {
173186
DynamicClass,
187+
Flow,
174188
ICalendarDate,
175189
IDateFilter,
176190
IDefaultSelect,
@@ -179,7 +193,10 @@
179193
IMarker,
180194
InternalModuleValue,
181195
ITimeValue,
196+
MenuChildCmp,
197+
MonthYearInputRef,
182198
PresetRange,
199+
TimePickerRef,
183200
WeekStartNum,
184201
WeekStartStr,
185202
} from '../interfaces';
@@ -195,6 +212,7 @@
195212
'dpOpen',
196213
'autoApply',
197214
'timeUpdate',
215+
'flow-step',
198216
]);
199217
const props = defineProps({
200218
internalModelValue: { type: [Date, Array] as PropType<InternalModuleValue>, default: null },
@@ -265,12 +283,17 @@
265283
readonly: { type: Boolean as PropType<boolean>, default: false },
266284
multiDates: { type: Boolean as PropType<boolean>, default: false },
267285
presetRanges: { type: Array as PropType<PresetRange[]>, default: () => [] },
286+
flow: { type: Array as PropType<Flow>, default: () => [] },
268287
});
269288
const slots = useSlots();
270289
const calendarWrapperRef = ref(null);
290+
const childrenMounted = reactive({ timePicker: false, monthYearInput: false, calendar: false });
291+
const monthYearInputRefs = ref<MonthYearInputRef[]>([]);
292+
const timePickerRef = ref<TimePickerRef | null>(null);
271293
const dpMenuRef = ref(null);
272294
const calendarWidth = ref(0);
273295
const menuMount = ref(false);
296+
const flowStep = ref(0);
274297
275298
onMounted(() => {
276299
menuMount.value = true;
@@ -294,6 +317,18 @@
294317
document.removeEventListener('resize', getCalendarWidth);
295318
});
296319
320+
const updateFlowStep = (): void => {
321+
if (props.flow?.length && flowStep.value !== -1) {
322+
flowStep.value += 1;
323+
emit('flow-step', flowStep.value);
324+
handleFlow();
325+
}
326+
};
327+
328+
const resetFlow = (): void => {
329+
flowStep.value = -1;
330+
};
331+
297332
const {
298333
updateTime,
299334
updateMonthYear,
@@ -322,7 +357,7 @@
322357
isHoverDateStartEnd,
323358
isHoverDate,
324359
presetDateRange,
325-
} = useCalendar(props, emit);
360+
} = useCalendar(props, emit, updateFlowStep);
326361
327362
const calendarSlots = mapSlots(slots, 'calendar');
328363
const actionSlots = mapSlots(slots, 'action');
@@ -494,4 +529,43 @@
494529
emit('selectDate');
495530
}
496531
};
532+
533+
const childMount = (cmp: MenuChildCmp): void => {
534+
if (props.flow?.length) {
535+
childrenMounted[cmp] = true;
536+
537+
if (!Object.keys(childrenMounted).filter((key) => !childrenMounted[key as MenuChildCmp]).length) {
538+
handleFlow();
539+
}
540+
}
541+
};
542+
543+
const handleFlow = (): void => {
544+
if (props.flow[flowStep.value] === 'month') {
545+
if (monthYearInputRefs.value[0]) {
546+
monthYearInputRefs.value[0].toggleMonthPicker(true);
547+
}
548+
}
549+
if (props.flow[flowStep.value] === 'year') {
550+
if (monthYearInputRefs.value) {
551+
monthYearInputRefs.value[0].toggleYearPicker(true);
552+
}
553+
}
554+
if (props.flow[flowStep.value] === 'calendar') {
555+
if (timePickerRef.value) {
556+
timePickerRef.value.toggleTimePicker(false, true);
557+
}
558+
}
559+
if (props.flow[flowStep.value] === 'time') {
560+
if (timePickerRef.value) {
561+
timePickerRef.value.toggleTimePicker(true, true);
562+
}
563+
}
564+
const flowValue = props.flow[flowStep.value];
565+
if (flowValue === 'hours' || flowValue === 'minutes' || flowValue === 'seconds') {
566+
if (timePickerRef.value) {
567+
timePickerRef.value.toggleTimePicker(true, true, flowValue);
568+
}
569+
}
570+
};
497571
</script>

src/Vue3DatePicker/components/MonthYearInput.vue

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@
163163
</template>
164164

165165
<script lang="ts" setup>
166-
import { computed, PropType, ref } from 'vue';
166+
import { computed, onMounted, PropType, ref } from 'vue';
167167
168168
import { ChevronLeftIcon, ChevronRightIcon, CalendarIcon } from './Icons';
169169
import SelectionGrid from './SelectionGrid.vue';
@@ -173,7 +173,7 @@
173173
import { useTransitions } from './composition/transition';
174174
import { getMonth, getYear } from 'date-fns';
175175
176-
const emit = defineEmits(['update:month', 'update:year', 'monthYearSelect']);
176+
const emit = defineEmits(['update:month', 'update:year', 'monthYearSelect', 'mount', 'reset-flow']);
177177
const props = defineProps({
178178
months: { type: Array as PropType<IDefaultSelect[]>, default: () => [] },
179179
years: { type: Array as PropType<IDefaultSelect[]>, default: () => [] },
@@ -195,16 +195,20 @@
195195
const showYearPicker = ref(false);
196196
const { handleMonthYearChange } = useMontYearPick(props, emit);
197197
198+
onMounted(() => {
199+
emit('mount');
200+
});
201+
198202
const onMonthUpdate = (month: number): void => {
199203
emit('update:month', month);
200204
emit('monthYearSelect');
201-
toggleMonthPicker();
205+
toggleMonthPicker(true);
202206
};
203207
204208
const onYearUpdate = (year: number): void => {
205209
emit('update:year', year);
206210
emit('monthYearSelect', true);
207-
toggleYearPicker();
211+
toggleYearPicker(true);
208212
};
209213
210214
const minYear = computed(() => (props.minDate ? getYear(new Date(props.minDate)) : null));
@@ -263,15 +267,28 @@
263267
return true;
264268
});
265269
266-
const toggleMonthPicker = (): void => {
270+
const toggleMonthPicker = (flow = false): void => {
271+
checkFlow(flow);
267272
showMonthPicker.value = !showMonthPicker.value;
268273
};
269274
270-
const toggleYearPicker = (): void => {
275+
const toggleYearPicker = (flow = false): void => {
276+
checkFlow(flow);
271277
showYearPicker.value = !showYearPicker.value;
272278
};
273279
280+
const checkFlow = (flow: boolean): void => {
281+
if (!flow) {
282+
emit('reset-flow');
283+
}
284+
};
285+
274286
const handleYear = (increment = false): void => {
275287
emit('update:year', increment ? props.year + 1 : props.year - 1);
276288
};
289+
290+
defineExpose({
291+
toggleMonthPicker,
292+
toggleYearPicker,
293+
});
277294
</script>

src/Vue3DatePicker/components/SelectionGrid.vue

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
aria-label="Toggle overlay"
3333
:class="actionButtonClass"
3434
tabindex="0"
35-
@click="$emit('toggle')"
36-
@keydown.enter="$emit('toggle')"
35+
@click="toggle"
36+
@keydown.enter="toggle"
3737
>
3838
<slot name="button-icon" />
3939
</div>
@@ -47,7 +47,7 @@
4747
import { IDefaultSelect, DynamicClass } from '../interfaces';
4848
import { getKey, unrefElement } from '../utils/util';
4949
50-
const emit = defineEmits(['update:modelValue', 'selected', 'toggle']);
50+
const emit = defineEmits(['update:modelValue', 'selected', 'toggle', 'reset-flow']);
5151
5252
const props = defineProps({
5353
items: { type: Array as PropType<IDefaultSelect[][]>, default: () => [] },
@@ -167,4 +167,9 @@
167167
emit('selected');
168168
}
169169
};
170+
171+
const toggle = () => {
172+
emit('toggle');
173+
emit('reset-flow');
174+
};
170175
</script>

0 commit comments

Comments
 (0)