Create dialog opening from and closing to

This commit is contained in:
Marcos Moura 2016-11-17 03:05:25 -02:00
parent 2021637830
commit 40a4213b98
3 changed files with 144 additions and 54 deletions

View file

@ -2,7 +2,7 @@
<demo-page label="Components - Dialog">
<div slot="examples">
<demo-example label="Default" size="2">
<md-dialog ref="dialog">
<md-dialog md-open-from="#trigger" md-close-to="#trigger" ref="dialog">
<div class="md-dialog-content">
<form>
<md-input-container>
@ -15,7 +15,7 @@
<md-button class="md-primary md-raised" @click="closeDialog">Close</md-button>
</md-dialog>
<md-button class="md-primary md-raised" @click="openDialog">Open</md-button>
<md-button class="md-primary md-raised" id="trigger" @click="openDialog">Open</md-button>
</demo-example>
</div>

View file

@ -1,44 +1,64 @@
@import '../../core/stylesheets/variables.scss';
.md-dialog {
min-width: 280px;
max-width: 80%;
max-height: 80%;
overflow: hidden;
.md-dialog-container {
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
pointer-events: none;
position: fixed;
top: 50%;
left: 50%;
z-index: 110;
outline: none;
border-radius: 2px;
opacity: 0;
filter: drop-shadow(0 7px 8px rgba(#000, $shadow-key-umbra-opacity))
drop-shadow(0 12px 17px rgba(#000, $shadow-key-penumbra-opacity))
drop-shadow(0 5px 22px rgba(#000, $shadow-ambient-shadow-opacity));
clip-path: inset(0 7% 12% 7%);
transform: translate3D(-50%, -60%, 0) scale(.85);
transition: transform $swift-ease-out-duration $swift-ease-out-timing-function,
opacity .3s $swift-ease-out-timing-function,
clip-path .3s .1s $swift-ease-out-timing-function;
transition-delay: 0;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 108;
&.md-active {
pointer-events: auto;
opacity: 1;
clip-path: inset(-22px -22px -22px -22px);
transition: transform $swift-ease-out-duration $swift-ease-out-timing-function,
opacity .5s $swift-ease-out-timing-function,
clip-path .4s .1s $swift-ease-out-timing-function;
transition-delay: 0;
transform: translate3D(-50%, -50%, 0) scale(1);
}
}
.md-dialog-container {
padding: 24px;
.md-dialog {
opacity: 1 !important;
transform: scale(1) !important;
transition: $swift-ease-out;
transform-property: opacity, transform;
> * {
opacity: 1;
}
}
}
}
.md-dialog-backdrop {
position: fixed;
z-index: 109;
}
.md-dialog {
min-width: 280px;
max-width: 80%;
max-height: 80%;
overflow: hidden;
position: relative;
z-index: 110;
outline: none;
border-radius: 2px;
opacity: 0;
box-shadow: $material-shadow-14dp;
transform: scale(.9, .85);
transition: opacity $swift-ease-out-duration $swift-ease-out-timing-function,
transform $swift-ease-out-duration .05s $swift-ease-out-timing-function;
will-change: opacity, transform;
&.md-transition-off {
transition: none;
}
> * {
opacity: 0;
transition: $swift-ease-out;
transition-property: opacity;
transition-delay: .1s;
will-change: opacity;
}
}

View file

@ -1,10 +1,10 @@
<template>
<div class="md-dialog" tabindex="0">
<div class="md-dialog-container">
<div class="md-dialog-container" :class="classes" @keyup.esc="mdEscToClose && close()" tabindex="0">
<div class="md-dialog" ref="dialog" :style="styles" :class="dialogClasses">
<slot></slot>
<md-backdrop class="md-dialog-backdrop" ref="backdrop" @close="close"></md-backdrop>
</div>
<md-backdrop class="md-dialog-backdrop" :class="classes" v-if="mdBackdrop" ref="backdrop" @close="mdClickOutsideToClose && close()"></md-backdrop>
</div>
</template>
@ -14,31 +14,99 @@
import transitionEndEventName from '../../core/utils/transitionEndEventName';
export default {
props: {
mdClickOutsideToClose: {
type: Boolean,
default: true
},
mdEscToClose: {
type: Boolean,
default: true
},
mdBackdrop: {
type: Boolean,
default: true
},
mdOpenFrom: String,
mdCloseTo: String,
mdFullscreen: {
type: Boolean,
default: false
}
},
data: () => ({
active: false
active: false,
transitionOff: false,
dialogTransform: '',
dialogTransformOrigin: ''
}),
computed: {
classes() {
return {
'md-fullscreen': this.mdFullscreen,
'md-active': this.active
};
},
dialogClasses() {
return {
'md-transition-off': this.transitionOff
};
},
styles() {
return {
transform: this.dialogTransform,
'transform-origin': this.dialogTransformOrigin
};
}
},
methods: {
open() {
this.close();
this.$root.$el.appendChild(this.dialogElement);
this.$root.$el.appendChild(this.backdropElement);
removeDialog() {
this.$el.parentNode.removeChild(this.$el);
},
calculateDialogPos(ref) {
const reference = document.querySelector(ref);
getComputedStyle(this.dialogElement).opacity;
this.dialogElement.focus();
this.dialogElement.classList.add('md-active');
this.backdropElement.classList.add('md-active');
if (reference) {
const openFromRect = reference.getBoundingClientRect();
const dialogRect = this.dialogInnerElement.getBoundingClientRect();
const topDistance = dialogRect.top - openFromRect.top;
const leftDistance = dialogRect.left - openFromRect.left;
const widthInScale = openFromRect.width / dialogRect.width;
const heightInScale = openFromRect.height / dialogRect.height;
this.dialogTransform = `translate3D(-${leftDistance}px, -${topDistance}px, 0) scale(${widthInScale}, ${heightInScale})`;
this.dialogTransformOrigin = 'top left';
}
},
open() {
this.$root.$el.appendChild(this.dialogElement);
this.transitionOff = true;
this.calculateDialogPos(this.mdOpenFrom);
window.setTimeout(() => {
this.dialogElement.focus();
this.transitionOff = false;
this.active = true;
});
},
close() {
if (this.$root.$el.contains(this.dialogElement)) {
let cleanElement = () => {
this.dialogElement.removeEventListener(transitionEndEventName, close);
this.dialogInnerElement.removeEventListener(transitionEndEventName, cleanElement);
this.$root.$el.removeChild(this.dialogElement);
this.$root.$el.removeChild(this.backdropElement);
this.dialogTransform = '';
this.dialogTransformOrigin = '';
};
this.dialogElement.classList.remove('md-active');
this.backdropElement.classList.remove('md-active');
this.dialogElement.addEventListener(cleanElement, close);
this.dialogTransform = '';
this.dialogTransformOrigin = '';
this.calculateDialogPos(this.mdCloseTo);
window.setTimeout(() => {
this.active = false;
this.dialogInnerElement.addEventListener(transitionEndEventName, cleanElement);
});
}
}
},
@ -46,10 +114,12 @@
this.$nextTick(() => {
this.rootElement = this.$root.$el;
this.dialogElement = this.$el;
this.backdropElement = this.$refs.backdrop.$el;
this.$el.parentNode.removeChild(this.$el);
this.$el.removeChild(this.$refs.backdrop.$el);
this.dialogInnerElement = this.$refs.dialog;
this.removeDialog();
});
},
beforeDestroy() {
this.removeDialog();
}
};
</script>