Files
nocodb/packages/nc-gui/components/nc/DatePicker.vue
2025-04-22 14:15:55 +00:00

175 lines
4.5 KiB
Vue

<script lang="ts" setup>
import dayjs from 'dayjs'
interface Props {
size?: 'medium'
selectedDate?: dayjs.Dayjs | null
pageDate?: dayjs.Dayjs
isCellInputField?: boolean
type: 'date' | 'time' | 'year' | 'month'
isOpen: boolean
showCurrentDateOption?: boolean | 'disabled'
isMondayFirst?: boolean
timezone?: string
}
const props = withDefaults(defineProps<Props>(), {
size: 'medium',
selectedDate: null,
pageDate: () => dayjs(),
isCellInputField: false,
type: 'date',
isOpen: false,
isMondayFirst: true,
})
const emit = defineEmits(['update:selectedDate', 'update:pageDate', 'update:selectedWeek', 'currentDate'])
const dayjsTz = (value?: string | null | dayjs.Dayjs, format?: string) => {
if (typeof value === 'object') {
return value
}
if (props?.timezone) {
if (!format) {
return dayjs.tz(value, props.timezone)
} else {
return dayjs.tz(value, format, props.timezone)
}
} else {
return dayjs(value, format)
}
}
// Page date is the date we use to manage which month/date that is currently being displayed
const pageDate = useVModel(props, 'pageDate', emit)
const selectedDate = useVModel(props, 'selectedDate', emit)
const { type, isOpen } = toRefs(props)
const localPageDate = ref()
const localSelectedDate = ref()
const pickerType = ref<Props['type'] | undefined>()
const pickerStack = ref<Props['type'][]>([])
const tempPickerType = computed(() => pickerType.value || type.value)
const handleUpdatePickerType = (value?: Props['type']) => {
if (value) {
pickerType.value = value
pickerStack.value.push(value)
} else {
if (pickerStack.value.length > 1) {
pickerStack.value.pop()
const lastPicker = pickerStack.value.pop()
pickerType.value = lastPicker
} else {
pickerStack.value = []
pickerType.value = type.value
}
}
}
const localStatePageDate = computed({
get: () => {
if (localPageDate.value) {
return localPageDate.value
}
return pageDate.value
},
set: (value) => {
pageDate.value = value
localPageDate.value = value
emit('update:pageDate', value)
},
})
const localStateSelectedDate = computed({
get: () => {
if (localSelectedDate.value) {
return localSelectedDate.value
}
return pageDate.value
},
set: (value: dayjs.Dayjs) => {
if (!value.isValid()) return
if (pickerType.value === type.value) {
localPageDate.value = dayjsTz(value.format('YYYY-MM-DD'))
emit('update:selectedDate', dayjsTz(value.format('YYYY-MM-DD')))
localSelectedDate.value = undefined
return
}
if (['date', 'month'].includes(type.value)) {
if (pickerType.value === 'year') {
localSelectedDate.value = dayjsTz(localPageDate.value ?? localSelectedDate.value ?? selectedDate.value ?? dayjsTz()).year(
+value.format('YYYY'),
)
}
if (type.value !== 'month' && pickerType.value === 'month') {
localSelectedDate.value = dayjsTz(
localPageDate.value ?? localSelectedDate.value ?? selectedDate.value ?? dayjsTz(),
).month(+value.format('MM') - 1)
}
localPageDate.value = localSelectedDate.value
handleUpdatePickerType()
}
},
})
watch(isOpen, (next) => {
if (!next) {
pickerType.value = type.value
localPageDate.value = undefined
localSelectedDate.value = undefined
pickerStack.value = []
}
})
onUnmounted(() => {
pickerType.value = type.value
localPageDate.value = undefined
localSelectedDate.value = undefined
pickerStack.value = []
})
onMounted(() => {
localPageDate.value = undefined
localSelectedDate.value = undefined
pickerStack.value = []
})
</script>
<template>
<NcDateWeekSelector
v-if="tempPickerType === 'date'"
v-model:page-date="localStatePageDate"
v-model:selected-date="localStateSelectedDate"
:picker-type="pickerType"
:is-monday-first="props.isMondayFirst"
is-cell-input-field
size="medium"
:show-current-date-option="showCurrentDateOption"
@update:picker-type="handleUpdatePickerType"
@current-date="emit('currentDate', $event)"
/>
<NcMonthYearSelector
v-if="['month', 'year'].includes(tempPickerType)"
v-model:page-date="localStatePageDate"
v-model:selected-date="localStateSelectedDate"
:picker-type="pickerType"
:is-year-picker="tempPickerType === 'year'"
is-cell-input-field
size="medium"
:show-current-date-option="showCurrentDateOption"
@update:picker-type="handleUpdatePickerType"
@current-date="emit('currentDate', $event)"
/>
</template>
<style lang="scss" scoped></style>