Improved dialog stack handling of scrolling while the stack is open
This commit is contained in:
@@ -7,9 +7,24 @@
|
|||||||
</v-icon>
|
</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<slot name="toolbar"></slot>
|
<slot name="toolbar"></slot>
|
||||||
|
<template v-if="$slots.edit">
|
||||||
|
<v-spacer/>
|
||||||
|
<v-btn icon flat @click="isEditing = !isEditing">
|
||||||
|
<v-icon>
|
||||||
|
{{isEditing ? 'check' : 'create'}}
|
||||||
|
</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
</v-toolbar>
|
</v-toolbar>
|
||||||
<v-card-text id="base-dialog-body" v-scroll:#base-dialog-body="onScroll">
|
<v-card-text id="base-dialog-body" v-scroll:#base-dialog-body="onScroll">
|
||||||
<slot></slot>
|
<v-tabs-items :value="isEditing ? 1 : 0">
|
||||||
|
<v-tab-item>
|
||||||
|
<slot/>
|
||||||
|
</v-tab-item>
|
||||||
|
<v-tab-item lazy>
|
||||||
|
<slot name="edit"/>
|
||||||
|
</v-tab-item>
|
||||||
|
</v-tabs-items>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<slot name="actions"></slot>
|
<slot name="actions"></slot>
|
||||||
@@ -26,6 +41,7 @@
|
|||||||
},
|
},
|
||||||
data(){ return {
|
data(){ return {
|
||||||
offsetTop: 0,
|
offsetTop: 0,
|
||||||
|
isEditing: false,
|
||||||
}},
|
}},
|
||||||
methods: {
|
methods: {
|
||||||
onScroll(e){
|
onScroll(e){
|
||||||
|
|||||||
@@ -68,12 +68,16 @@
|
|||||||
return `left:${left}px; top:${top}px;`;
|
return `left:${left}px; top:${top}px;`;
|
||||||
},
|
},
|
||||||
enter(target, done){
|
enter(target, done){
|
||||||
if (!target.attributes['data-element-id']){
|
if (!target || !target.attributes['data-element-id']){
|
||||||
done();
|
done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let elementId = target.attributes['data-element-id'].value;
|
let elementId = target.attributes['data-element-id'].value;
|
||||||
let source = document.getElementById(elementId);
|
let source = document.getElementById(elementId);
|
||||||
|
if (!source){
|
||||||
|
done();
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Get the original styles so we can repair them later
|
// Get the original styles so we can repair them later
|
||||||
let originalStyle = {
|
let originalStyle = {
|
||||||
transform: target.style.transform,
|
transform: target.style.transform,
|
||||||
@@ -87,6 +91,7 @@
|
|||||||
// hide the source
|
// hide the source
|
||||||
source.style.transition = "none";
|
source.style.transition = "none";
|
||||||
source.style.opacity = "0";
|
source.style.opacity = "0";
|
||||||
|
this.hiddenElement = source;
|
||||||
|
|
||||||
// Instantly mock the source
|
// Instantly mock the source
|
||||||
target.style.transition = 'none';
|
target.style.transition = 'none';
|
||||||
@@ -105,16 +110,20 @@
|
|||||||
},
|
},
|
||||||
leave(target, done){
|
leave(target, done){
|
||||||
let elementId;
|
let elementId;
|
||||||
if (target.attributes['data-return-element-id']) {
|
if (target && target.attributes['data-return-element-id']) {
|
||||||
elementId = target.attributes['data-return-element-id'].value;
|
elementId = target.attributes['data-return-element-id'].value;
|
||||||
} else {
|
} else {
|
||||||
if (!target.attributes['data-element-id']){
|
if (!target || !target.attributes['data-element-id']){
|
||||||
done();
|
done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
elementId = target.attributes['data-element-id'].value;
|
elementId = target.attributes['data-element-id'].value;
|
||||||
}
|
}
|
||||||
let source = document.getElementById(elementId);
|
let source = document.getElementById(elementId);
|
||||||
|
if (!source){
|
||||||
|
done();
|
||||||
|
return;
|
||||||
|
}
|
||||||
let index = target.attributes['data-index'].value;
|
let index = target.attributes['data-index'].value;
|
||||||
if (index != 0){
|
if (index != 0){
|
||||||
// If we aren't the only dialog, we'll need compensate for offset
|
// If we aren't the only dialog, we'll need compensate for offset
|
||||||
@@ -122,21 +131,54 @@
|
|||||||
} else {
|
} else {
|
||||||
mockElement({source, target});
|
mockElement({source, target});
|
||||||
}
|
}
|
||||||
|
// If the source and the hidden Element are different
|
||||||
|
// hide the source and reveal the hidden element
|
||||||
|
let originalSourceTransition = source.style.transition;
|
||||||
|
if (this.hiddenElement !== source){
|
||||||
|
source.style.transition = "none";
|
||||||
|
source.style.opacity = "0";
|
||||||
|
this.hiddenElement.style.opacity = null;
|
||||||
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
let originalTransition = source.style.transition;
|
|
||||||
source.style.opacity = null;
|
source.style.opacity = null;
|
||||||
source.style.transition = 'none';
|
source.style.transition = 'none';
|
||||||
target.style.transition = `opacity ${MOCK_DURATION / 4}ms, pointer-events 0s`
|
target.style.transition = `opacity ${MOCK_DURATION / 4}ms, pointer-events 0s`
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
source.style.transition = originalTransition;
|
source.style.transition = originalSourceTransition;
|
||||||
target.style.opacity = "0";
|
target.style.opacity = "0";
|
||||||
target.style.pointerEvents = "none";
|
target.style.pointerEvents = "none";
|
||||||
target.style.setProperty('box-shadow', "none", 'important');
|
target.style.setProperty('box-shadow', "none", 'important');
|
||||||
setTimeout(done, MOCK_DURATION / 4);
|
setTimeout(done, MOCK_DURATION / 4);
|
||||||
});
|
});
|
||||||
}, MOCK_DURATION);
|
}, MOCK_DURATION);
|
||||||
|
},
|
||||||
|
noScroll(e){
|
||||||
|
console.log(e);
|
||||||
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
watch:{
|
||||||
|
dialogs(newDialogs) {
|
||||||
|
let el = document.documentElement;
|
||||||
|
if (newDialogs.length) {
|
||||||
|
this.top = el.scrollTop;
|
||||||
|
if (el.scrollHeight > el.clientHeight){
|
||||||
|
el.style.position = 'fixed';
|
||||||
|
el.style.top = `${-this.top}px`;
|
||||||
|
el.style.left = 0;
|
||||||
|
el.style.right = 0;
|
||||||
|
el.style.overflowY = 'scroll';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
el.style.position = null;
|
||||||
|
el.style.top = null;
|
||||||
|
el.style.left = null;
|
||||||
|
el.style.right = null;
|
||||||
|
el.style.overflowY = null;
|
||||||
|
el.scrollTop = this.top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ const transformedBoxShadow = (shadowString, deltaWidth, deltaHeight) => {
|
|||||||
|
|
||||||
export default function mockElement({source, target, offset = {x: 0, y: 0}}){
|
export default function mockElement({source, target, offset = {x: 0, y: 0}}){
|
||||||
if (!source || !target) throw `Can't mock without ${source ? 'target' : 'source'}` ;
|
if (!source || !target) throw `Can't mock without ${source ? 'target' : 'source'}` ;
|
||||||
sourceRect = source.getBoundingClientRect();
|
let sourceRect = source.getBoundingClientRect();
|
||||||
targetRect = target.getBoundingClientRect();
|
let targetRect = target.getBoundingClientRect();
|
||||||
|
|
||||||
// Get how must the target change to become the source
|
// Get how must the target change to become the source
|
||||||
const deltaWidth = sourceRect.width / targetRect.width;
|
const deltaWidth = sourceRect.width / targetRect.width;
|
||||||
|
|||||||
Reference in New Issue
Block a user