mirror of
https://bitbucket.org/studiotem/jandl-taskmanager-app.git
synced 2026-10-21 14:29:34 +00:00
fix(datepicker): improve focus handling and scroll position restoration in modal
This commit is contained in:
1 parent
056b27b016
commit
61fc55d313
3 files changed
+64
-9
No files matched your search
@@ -3,6 +3,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
preventInputFocus: false,
|
preventInputFocus: false,
|
||||||
|
savedScrollPosition: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -20,18 +21,44 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
onDateOpen($event) {
|
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;
|
this.preventInputFocus = true;
|
||||||
|
|
||||||
|
// Reset after datepicker is opened
|
||||||
|
setTimeout(() => {
|
||||||
|
this.preventInputFocus = false;
|
||||||
|
this.savedScrollPosition = null;
|
||||||
|
}, 500);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onInputFocus($event) {
|
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(() => {
|
setTimeout(() => {
|
||||||
if (this.preventInputFocus) {
|
target.blur();
|
||||||
$event.target.blur();
|
|
||||||
this.preventInputFocus = false;
|
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">
|
<div class="splitted-inputs">
|
||||||
<!-- TODO: Bialko validacie -->
|
<!-- TODO: Bialko validacie -->
|
||||||
|
<div
|
||||||
|
@click="handleDatepickerClick"
|
||||||
|
class="datepicker-wrapper left"
|
||||||
|
ref="datepicker-wrapper"
|
||||||
|
>
|
||||||
<Datepicker
|
<Datepicker
|
||||||
v-model="mastertask.deadline"
|
v-model="mastertask.deadline"
|
||||||
|
ref="datepicker"
|
||||||
:auto-apply="true"
|
:auto-apply="true"
|
||||||
@focus="onDateFocus"
|
|
||||||
:min-date="new Date()"
|
:min-date="new Date()"
|
||||||
class="modal-input left"
|
class="modal-input datepicker-input"
|
||||||
format="dd.MM.yyyy"
|
format="dd.MM.yyyy"
|
||||||
locale="sk"
|
locale="sk"
|
||||||
select-text="Vybrať"
|
select-text="Vybrať"
|
||||||
@@ -71,6 +76,7 @@
|
|||||||
:class="{ error: v$.mastertask.deadline.$errors?.length }"
|
:class="{ error: v$.mastertask.deadline.$errors?.length }"
|
||||||
:validations="v$.mastertask.deadline"
|
:validations="v$.mastertask.deadline"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<v-text-field
|
<v-text-field
|
||||||
class="modal-input right"
|
class="modal-input right"
|
||||||
@@ -454,6 +460,14 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
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() {
|
closeBothModals() {
|
||||||
this.$emit('close');
|
this.$emit('close');
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
@@ -770,4 +784,11 @@ export default {
|
|||||||
|
|
||||||
:deep(.v-field__clearable)
|
:deep(.v-field__clearable)
|
||||||
opacity: 1 !important
|
opacity: 1 !important
|
||||||
|
|
||||||
|
.datepicker-wrapper
|
||||||
|
width: 100%
|
||||||
|
.datepicker-input
|
||||||
|
width: 100% !important
|
||||||
|
height: 100%
|
||||||
|
pointer-events: none
|
||||||
</style>
|
</style>
|
||||||
@@ -4,14 +4,13 @@
|
|||||||
<button @click="$emit('removeTimeblock')" class="x-button">x</button>
|
<button @click="$emit('removeTimeblock')" class="x-button">x</button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@click="openDatepicker('datepicker')"
|
@click="handleDatepickerClick"
|
||||||
class="datepicker-wrapper"
|
class="datepicker-wrapper"
|
||||||
ref="datepicker-wrapper"
|
ref="datepicker-wrapper"
|
||||||
>
|
>
|
||||||
<Datepicker
|
<Datepicker
|
||||||
:model-value="timeblock.date"
|
:model-value="timeblock.date"
|
||||||
ref="datepicker"
|
ref="datepicker"
|
||||||
@open="onDateOpen"
|
|
||||||
@update:model-value="updateDate"
|
@update:model-value="updateDate"
|
||||||
format="dd.MM.yyyy"
|
format="dd.MM.yyyy"
|
||||||
locale="sk"
|
locale="sk"
|
||||||
@@ -104,6 +103,14 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
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) {
|
async openDatepicker(ref) {
|
||||||
this.$refs[ref].openMenu();
|
this.$refs[ref].openMenu();
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in new issue
Block a user