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: '' },
|
title: { type: String, default: '' },
|
||||||
draggable: { type: Boolean, default: true },
|
draggable: { type: Boolean, default: true },
|
||||||
autoFocus: { 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'])
|
const emit = defineEmits(['update:modelValue', 'opened', 'closed', 'submit'])
|
||||||
@ -97,17 +100,17 @@ onMounted(() => document.addEventListener('keydown', handleKeydown))
|
|||||||
onUnmounted(() => document.removeEventListener('keydown', handleKeydown))
|
onUnmounted(() => document.removeEventListener('keydown', handleKeydown))
|
||||||
|
|
||||||
function positionNearAnchor() {
|
function positionNearAnchor() {
|
||||||
if (!anchorRef.value) return
|
const anchor = props.anchorEl || anchorRef.value
|
||||||
const rect = anchorRef.value.getBoundingClientRect()
|
if (!anchor) return
|
||||||
// Place dialog below anchor with small vertical offset
|
const rect = anchor.getBoundingClientRect()
|
||||||
const offsetY = 8
|
const offsetY = 8 // vertical gap below the anchor
|
||||||
// Need dialog dimensions to clamp correctly; measure current or fallback estimates
|
|
||||||
const w = modalRef.value?.offsetWidth || dialogWidth.value || 320
|
const w = modalRef.value?.offsetWidth || dialogWidth.value || 320
|
||||||
const h = modalRef.value?.offsetHeight || dialogHeight.value || 200
|
const h = modalRef.value?.offsetHeight || dialogHeight.value || 200
|
||||||
const vw = window.innerWidth
|
const vw = window.innerWidth
|
||||||
const vh = window.innerHeight
|
const vh = window.innerHeight
|
||||||
let x = rect.left
|
let x = rect.left
|
||||||
let y = rect.bottom + offsetY
|
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))
|
x = clamp(x, margin, Math.max(margin, vw - w - margin))
|
||||||
y = clamp(y, margin, Math.max(margin, vh - h - margin))
|
y = clamp(y, margin, Math.max(margin, vh - h - margin))
|
||||||
modalPosition.value = { x, y }
|
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() {
|
function handleResize() {
|
||||||
if (!props.modelValue) return
|
if (!props.modelValue) return
|
||||||
// Re-clamp current position, and if not moved recalc near anchor
|
// Re-clamp current position, and if not moved recalc near anchor
|
||||||
|
@ -23,6 +23,8 @@ const emit = defineEmits(['clear-selection'])
|
|||||||
const calendarStore = useCalendarStore()
|
const calendarStore = useCalendarStore()
|
||||||
|
|
||||||
const showDialog = ref(false)
|
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 dialogMode = ref('create') // 'create' or 'edit'
|
||||||
const editingEventId = ref(null)
|
const editingEventId = ref(null)
|
||||||
const unsavedCreateId = ref(null)
|
const unsavedCreateId = ref(null)
|
||||||
@ -191,6 +193,12 @@ function loadWeekdayPatternFromStore(storePattern) {
|
|||||||
recurrenceWeekdays.value = [...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) {
|
function openCreateDialog(selectionData = null) {
|
||||||
calendarStore.$history?.beginCompound()
|
calendarStore.$history?.beginCompound()
|
||||||
if (unsavedCreateId.value && !eventSaved.value) {
|
if (unsavedCreateId.value && !eventSaved.value) {
|
||||||
@ -240,6 +248,8 @@ function openCreateDialog(selectionData = null) {
|
|||||||
})
|
})
|
||||||
unsavedCreateId.value = editingEventId.value
|
unsavedCreateId.value = editingEventId.value
|
||||||
|
|
||||||
|
// anchor to the starting day cell
|
||||||
|
anchorElement.value = resolveAnchorFromDate(start)
|
||||||
showDialog.value = true
|
showDialog.value = true
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
@ -344,6 +354,8 @@ function openEditDialog(payload) {
|
|||||||
occurrenceContext.value = { baseId, occurrenceIndex, weekday: null, occurrenceDate }
|
occurrenceContext.value = { baseId, occurrenceIndex, weekday: null, occurrenceDate }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// anchor to base event start date
|
||||||
|
anchorElement.value = resolveAnchorFromDate(event.startDate)
|
||||||
showDialog.value = true
|
showDialog.value = true
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
@ -553,7 +565,7 @@ const recurrenceSummary = computed(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<BaseDialog v-model="showDialog" @submit="saveEvent">
|
<BaseDialog v-model="showDialog" :anchor-el="anchorElement" @submit="saveEvent">
|
||||||
<template #title>
|
<template #title>
|
||||||
{{ dialogMode === 'create' ? 'Create Event' : 'Edit Event'
|
{{ dialogMode === 'create' ? 'Create Event' : 'Edit Event'
|
||||||
}}<template v-if="headerDateShort"> · {{ headerDateShort }}</template>
|
}}<template v-if="headerDateShort"> · {{ headerDateShort }}</template>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user