feat: add available range prop to SingleDatePicker for date selection constraints

This commit is contained in:
Astrian Zheng 2025-02-24 14:32:26 +11:00
parent bd4dd671ef
commit 13a55d7eda
Signed by: Astrian
SSH Key Fingerprint: SHA256:rVnhx3DAKjujCwWE13aDl7uV6+9U1MvydLkNRXJrBiA
2 changed files with 54 additions and 4 deletions

View File

@ -8,7 +8,7 @@ const date = ref(new Date())
<template> <template>
<div>{{date.toDateString()}}</div> <div>{{date.toDateString()}}</div>
<div class="container"> <div class="container">
<SingleDatePicker v-model="date" localization="zh-CN" @close="() => {}" /> <SingleDatePicker :available-range="[new Date(2025, 0, 1), null]" v-model="date" />
</div> </div>
</template> </template>

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, defineProps, watch, onMounted, toRefs, getCurrentInstance } from 'vue' import { ref, defineProps, watch, onMounted, toRefs, getCurrentInstance, PropType } from 'vue'
import { generateUniqueId, applyColor, getL10Weekday, getCalendarDates } from '../utils' import { generateUniqueId, applyColor, getL10Weekday, getCalendarDates } from '../utils'
interface SingleDatePickerPropsColorScheme { interface SingleDatePickerPropsColorScheme {
@ -10,6 +10,8 @@
reversedColor: string reversedColor: string
} }
type SingleDatePickerPropsAvailableDates = [Date | null, Date | null]
const props = defineProps({ const props = defineProps({
colorScheme: { colorScheme: {
type: Object as () => SingleDatePickerPropsColorScheme, type: Object as () => SingleDatePickerPropsColorScheme,
@ -29,6 +31,10 @@
modelValue: { modelValue: {
type: Date, type: Date,
required: false, required: false,
},
availableRange: {
type: Array as unknown as PropType<SingleDatePickerPropsAvailableDates>,
required: false,
} }
}) })
@ -40,6 +46,8 @@
const l10nDays = ref<string[]>([]) const l10nDays = ref<string[]>([])
const dates = ref<Date[]>([]) const dates = ref<Date[]>([])
const hasCloseListener = getCurrentInstance()?.vnode?.props?.onClose !== undefined const hasCloseListener = getCurrentInstance()?.vnode?.props?.onClose !== undefined
const availableRangeStart = ref<Date | null>(null)
const availableRangeEnd = ref<Date | null>(null)
const { colorScheme, localization } = toRefs(props) const { colorScheme, localization } = toRefs(props)
@ -51,6 +59,10 @@
dates.value = getCalendarDates(currentMonth.value, currentYear.value) dates.value = getCalendarDates(currentMonth.value, currentYear.value)
}) })
watch([props.availableRange], () => {
calculateAvailableRange()
})
onMounted(() => { onMounted(() => {
applyColor(uniqueId, colorScheme.value) applyColor(uniqueId, colorScheme.value)
l10nDays.value = getL10Weekday(localization?.value || navigator.languages[0]) l10nDays.value = getL10Weekday(localization?.value || navigator.languages[0])
@ -63,6 +75,8 @@
currentYear.value = new Date().getFullYear() currentYear.value = new Date().getFullYear()
} }
dates.value = getCalendarDates(currentMonth.value, currentYear.value) dates.value = getCalendarDates(currentMonth.value, currentYear.value)
calculateAvailableRange()
}) })
function goToLastMonth() { function goToLastMonth() {
@ -83,8 +97,8 @@
} }
} }
function notAvailable(date: Date) { function notAvailable(date: Date): boolean {
return currentMonth.value !== date.getMonth() //TODO: available date ranges return currentMonth.value !== date.getMonth() || (availableRangeStart.value !== null && date < availableRangeStart.value) || (availableRangeEnd.value !== null && date > availableRangeEnd.value)
} }
function selectDate(date: Date) { function selectDate(date: Date) {
@ -109,6 +123,42 @@
emit('close') emit('close')
} }
function calculateAvailableRange() {
if (!props.availableRange) {
availableRangeStart.value = null
availableRangeEnd.value = null
return
}
if (props.availableRange.length !== 2) {
console.warn('Invalid availableRange: The length of the array should be 2. The parameter will be ignored.')
availableRangeStart.value = null
availableRangeEnd.value = null
return
}
const [start, end] = props.availableRange
if (start && end) {
if (start > end) {
availableRangeStart.value = end
availableRangeEnd.value = start
} else {
availableRangeStart.value = start
availableRangeEnd.value = end
}
} else if (start && !end) {
availableRangeStart.value = start
availableRangeEnd.value = null
} else if (!start && end) {
availableRangeStart.value = null
availableRangeEnd.value = end
} else {
availableRangeStart.value = null
availableRangeEnd.value = null
}
}
</script> </script>
<template> <template>