Open Event dialog right below the day pointed to.
This commit is contained in:
parent
7ed6fd9b29
commit
6a31f30e6c
@ -6,6 +6,9 @@ const props = defineProps({
|
||||
title: { type: String, default: '' },
|
||||
draggable: { type: Boolean, default: true },
|
||||
autoFocus: { type: Boolean, default: true },
|
||||
// Optional external anchor element (e.g., a day cell) to position the dialog below.
|
||||
// If not provided, falls back to internal anchorRef span (original behavior).
|
||||
anchorEl: { type: Object, default: null },
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'opened', 'closed', 'submit'])
|
||||
@ -97,17 +100,17 @@ onMounted(() => document.addEventListener('keydown', handleKeydown))
|
||||
onUnmounted(() => document.removeEventListener('keydown', handleKeydown))
|
||||
|
||||
function positionNearAnchor() {
|
||||
if (!anchorRef.value) return
|
||||
const rect = anchorRef.value.getBoundingClientRect()
|
||||
// Place dialog below anchor with small vertical offset
|
||||
const offsetY = 8
|
||||
// Need dialog dimensions to clamp correctly; measure current or fallback estimates
|
||||
const anchor = props.anchorEl || anchorRef.value
|
||||
if (!anchor) return
|
||||
const rect = anchor.getBoundingClientRect()
|
||||
const offsetY = 8 // vertical gap below the anchor
|
||||
const w = modalRef.value?.offsetWidth || dialogWidth.value || 320
|
||||
const h = modalRef.value?.offsetHeight || dialogHeight.value || 200
|
||||
const vw = window.innerWidth
|
||||
const vh = window.innerHeight
|
||||
let x = rect.left
|
||||
let y = rect.bottom + offsetY
|
||||
// If anchor is wider than dialog and would overflow right edge, clamp; otherwise keep left align
|
||||
x = clamp(x, margin, Math.max(margin, vw - w - margin))
|
||||
y = clamp(y, margin, Math.max(margin, vh - h - margin))
|
||||
modalPosition.value = { x, y }
|
||||
@ -132,6 +135,16 @@ watch(
|
||||
},
|
||||
)
|
||||
|
||||
// Reposition if anchorEl changes while open and user hasn't dragged dialog yet
|
||||
watch(
|
||||
() => props.anchorEl,
|
||||
() => {
|
||||
if (props.modelValue && !hasMoved.value) {
|
||||
nextTick(() => positionNearAnchor())
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
function handleResize() {
|
||||
if (!props.modelValue) return
|
||||
// Re-clamp current position, and if not moved recalc near anchor
|
||||
|
@ -23,6 +23,8 @@ const emit = defineEmits(['clear-selection'])
|
||||
const calendarStore = useCalendarStore()
|
||||
|
||||
const showDialog = ref(false)
|
||||
// Anchoring: element of the DayCell representing the event's start date.
|
||||
const anchorElement = ref(null)
|
||||
const dialogMode = ref('create') // 'create' or 'edit'
|
||||
const editingEventId = ref(null)
|
||||
const unsavedCreateId = ref(null)
|
||||
@ -191,6 +193,12 @@ function loadWeekdayPatternFromStore(storePattern) {
|
||||
recurrenceWeekdays.value = [...storePattern]
|
||||
}
|
||||
|
||||
function resolveAnchorFromDate(dateStr) {
|
||||
if (!dateStr) return null
|
||||
// Expect day cells to have data-date attribute (see CalendarDay / DayCell components)
|
||||
return document.querySelector(`[data-date='${dateStr}']`)
|
||||
}
|
||||
|
||||
function openCreateDialog(selectionData = null) {
|
||||
calendarStore.$history?.beginCompound()
|
||||
if (unsavedCreateId.value && !eventSaved.value) {
|
||||
@ -240,6 +248,8 @@ function openCreateDialog(selectionData = null) {
|
||||
})
|
||||
unsavedCreateId.value = editingEventId.value
|
||||
|
||||
// anchor to the starting day cell
|
||||
anchorElement.value = resolveAnchorFromDate(start)
|
||||
showDialog.value = true
|
||||
|
||||
nextTick(() => {
|
||||
@ -344,6 +354,8 @@ function openEditDialog(payload) {
|
||||
occurrenceContext.value = { baseId, occurrenceIndex, weekday: null, occurrenceDate }
|
||||
}
|
||||
}
|
||||
// anchor to base event start date
|
||||
anchorElement.value = resolveAnchorFromDate(event.startDate)
|
||||
showDialog.value = true
|
||||
|
||||
nextTick(() => {
|
||||
@ -553,7 +565,7 @@ const recurrenceSummary = computed(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BaseDialog v-model="showDialog" @submit="saveEvent">
|
||||
<BaseDialog v-model="showDialog" :anchor-el="anchorElement" @submit="saveEvent">
|
||||
<template #title>
|
||||
{{ dialogMode === 'create' ? 'Create Event' : 'Edit Event'
|
||||
}}<template v-if="headerDateShort"> · {{ headerDateShort }}</template>
|
||||
|
Loading…
x
Reference in New Issue
Block a user