fix(datepicker): improve focus handling and scroll position restoration in modal

This commit is contained in:
Matej Glasnák committed 2025-10-14 01:42:41 +02:00
1 parent 056b27b016
commit 61fc55d313
3 files changed
+64 -9

No files matched your search

@@ -3,6 +3,7 @@ export default {
data() {
return {
preventInputFocus: false,
savedScrollPosition: null,
};
},
@@ -20,18 +21,44 @@ export default {
},
onDateOpen($event) {
if ($event == undefined) {
// $event should be the element reference (or any truthy value to trigger saving)
if ($event) {
// Find the scrollable modal container
const modalContent = document.querySelector('.v-dialog .modal-content');
if (modalContent) {
this.savedScrollPosition = modalContent.scrollTop;
}
this.preventInputFocus = true;
// Reset after datepicker is opened
setTimeout(() => {
this.preventInputFocus = false;
this.savedScrollPosition = null;
}, 500);
}
},
onInputFocus($event) {
// If we have a saved scroll position and an unwanted focus happened
if (this.preventInputFocus && this.savedScrollPosition !== null) {
const target = $event.target;
// Only intercept text input focus (autocomplete fields)
if (target.tagName === 'INPUT' && target.type === 'text') {
// Blur the focused element
setTimeout(() => {
if (this.preventInputFocus) {
$event.target.blur();
this.preventInputFocus = false;
target.blur();
const modalContent = document.querySelector(
'.v-dialog .modal-content',
);
if (modalContent && this.savedScrollPosition !== null) {
modalContent.scrollTop = this.savedScrollPosition;
}
}, 0);
}
}
}, 100);
},
},
};
@@ -57,12 +57,17 @@
<div class="splitted-inputs">
<!-- TODO: Bialko validacie -->
<div
@click="handleDatepickerClick"
class="datepicker-wrapper left"
ref="datepicker-wrapper"
>
<Datepicker
v-model="mastertask.deadline"
ref="datepicker"
:auto-apply="true"
@focus="onDateFocus"
:min-date="new Date()"
class="modal-input left"
class="modal-input datepicker-input"
format="dd.MM.yyyy"
locale="sk"
select-text="Vybrať"
@@ -71,6 +76,7 @@
:class="{ error: v$.mastertask.deadline.$errors?.length }"
:validations="v$.mastertask.deadline"
/>
</div>
<v-text-field
class="modal-input right"
@@ -454,6 +460,14 @@ export default {
},
methods: {
handleDatepickerClick() {
// Pass the datepicker wrapper element reference to the mixin
const scrollTarget = this.$refs['datepicker-wrapper'];
this.onDateOpen(scrollTarget);
// Open the datepicker
this.$refs['datepicker'].openMenu();
},
closeBothModals() {
this.$emit('close');
this.visible = false;
@@ -770,4 +784,11 @@ export default {
:deep(.v-field__clearable)
opacity: 1 !important
.datepicker-wrapper
width: 100%
.datepicker-input
width: 100% !important
height: 100%
pointer-events: none
</style>
@@ -4,14 +4,13 @@
<button @click="$emit('removeTimeblock')" class="x-button">x</button>
</div>
<div
@click="openDatepicker('datepicker')"
@click="handleDatepickerClick"
class="datepicker-wrapper"
ref="datepicker-wrapper"
>
<Datepicker
:model-value="timeblock.date"
ref="datepicker"
@open="onDateOpen"
@update:model-value="updateDate"
format="dd.MM.yyyy"
locale="sk"
@@ -104,6 +103,14 @@ export default {
},
methods: {
handleDatepickerClick() {
// Pass the datepicker wrapper element reference to the mixin
const scrollTarget = this.$refs['datepicker-wrapper'];
this.onDateOpen(scrollTarget);
// Open the datepicker
this.openDatepicker('datepicker');
},
async openDatepicker(ref) {
this.$refs[ref].openMenu();
},