recreate ripple component and add a global toggle to it

This commit is contained in:
Marcos Moura 2017-01-09 23:02:55 -02:00
parent 8db86ef04b
commit 08ea6313c6
4 changed files with 195 additions and 35 deletions

View file

@ -1,5 +1,5 @@
import 'scopedQuerySelectorShim/dist/scopedQuerySelectorShim';
import './mdInkRipple.vue';
import mdInkRipple from './mdInkRipple.vue';
export default function install(Vue) {
let rippleParentClass = 'md-ink-ripple';
@ -116,31 +116,5 @@ export default function install(Vue) {
});
});
Vue.component('md-ink-ripple', {
props: {
mdDisabled: Boolean
},
render(createElement) {
return createElement('div', {
staticClass: 'md-ink-ripple'
});
},
watch: {
mdDisabled() {
if (this.mdDisabled) {
unregisterMouseEvent(this.$el.parentNode);
} else {
createRipple(this.$el.parentNode, this.$el);
}
}
},
mounted() {
if (!this.mdDisabled) {
createRipple(this.$el.parentNode, this.$el);
}
},
destroyed() {
unregisterMouseEvent(this.$el.parentNode);
}
});
Vue.component('md-ink-ripple', Vue.extend(mdInkRipple));
}

View file

@ -8,25 +8,32 @@
right: 0;
bottom: 0;
left: 0;
mask-image: radial-gradient(circle, white 100%, black 100%);
-webkit-mask-image: radial-gradient(circle, white 100%, black 100%);
transition: $swift-ease-in;
}
.md-ripple {
position: absolute;
transform: scale(0);
background-color: currentColor;
opacity: .26;
border-radius: 50%;
opacity: .2;
transform: scale(0) translateZ(0);
transition: none;
will-change: background-color, opacity, transform, width, height, top, left;
&.md-fadeout {
opacity: 0;
transition: $swift-ease-out;
transition-duration: .6s;
}
&.md-active {
animation: ripple 1s $swift-ease-out-timing-function;
animation: ripple 1s $swift-ease-out-timing-function forwards;
}
}
@keyframes ripple {
to {
transform: scale(1.5);
opacity: 0;
transform: scale(2.2) translateZ(0);
}
}

View file

@ -1 +1,179 @@
<template>
<div class="md-ink-ripple" v-if="!disabled">
<div class="md-ripple" :class="classes" :style="styles" ref="ripple"></div>
</div>
</template>
<style lang="scss" src="./mdInkRipple.scss"></style>
<script>
export default {
props: {
mdDisabled: Boolean
},
data: () => ({
rippleElement: null,
parentElement: null,
parentDimensions: {
width: null,
height: null,
top: null,
left: null
},
awaitingComplete: false,
hasCompleted: false,
fadeOut: false,
active: false
}),
computed: {
classes() {
return {
'md-fadeout': this.fadeOut,
'md-active': this.active
};
},
styles() {
return {
width: this.parentDimensions.width,
height: this.parentDimensions.height,
top: this.parentDimensions.top,
left: this.parentDimensions.left
};
},
disabled() {
return this.mdDisabled || !this.$material.inkRipple;
}
},
watch: {
disabled(disabled) {
if (!disabled) {
this.init();
} else {
this.destroy();
}
}
},
methods: {
checkAvailablePositions(element) {
const availablePositions = ['relative', 'absolute', 'fixed'];
return availablePositions.indexOf(getComputedStyle(element).position) > -1;
},
getClosestPositionedParent(element) {
const parent = element.parentNode;
if (!element || !parent || parent.tagName.toLowerCase() === 'body') {
return false;
}
if (this.checkAvailablePositions(element)) {
return element;
}
return this.getClosestPositionedParent(element.parentNode);
},
getParentSize() {
const parent = this.parentElement;
return Math.round(Math.max(parent.offsetWidth, parent.offsetHeight)) + 'px';
},
getClickPosition(event) {
const rect = this.parentElement.getBoundingClientRect();
const top = event.pageY - rect.top - this.$refs.ripple.offsetHeight / 2 - document.body.scrollTop + 'px';
const left = event.pageX - rect.left - this.$refs.ripple.offsetWidth / 2 - document.body.scrollLeft + 'px';
return {
top,
left
};
},
setDimensions() {
const size = this.getParentSize();
this.parentDimensions.width = size;
this.parentDimensions.height = size;
},
setPositions(event) {
const positions = this.getClickPosition(event);
this.parentDimensions.top = positions.top;
this.parentDimensions.left = positions.left;
},
clearState() {
this.active = false;
this.fadeOut = false;
this.hasCompleted = false;
this.setDimensions();
window.clearTimeout(this.awaitingComplete);
document.body.removeEventListener('mouseup', this.endRipple);
},
startRipple(event) {
window.requestAnimationFrame(() => {
this.clearState();
this.awaitingComplete = window.setTimeout(() => {
this.hasCompleted = true;
}, 400);
document.body.addEventListener('mouseup', this.endRipple);
this.setPositions(event);
window.setTimeout(() => {
this.active = true;
});
});
},
endRipple() {
if (this.hasCompleted) {
this.fadeOut = true;
} else {
this.awaitingComplete = window.setTimeout(() => {
this.fadeOut = true;
}, 200);
}
document.body.removeEventListener('mouseup', this.endRipple);
},
registerMouseEvent() {
this.parentElement.addEventListener('mousedown', this.startRipple);
},
unregisterMouseEvent() {
if (this.parentElement) {
this.parentElement.removeEventListener('mousedown', this.startRipple);
document.body.removeEventListener('mouseup', this.endRipple);
}
},
init() {
this.$nextTick(() => {
this.rippleElement = this.$el;
this.parentElement = this.getClosestPositionedParent(this.$el.parentNode);
if (!this.parentElement) {
this.$destroy();
} else {
this.rippleElement.parentNode.removeChild(this.rippleElement);
this.parentElement.appendChild(this.rippleElement);
this.registerMouseEvent();
this.setDimensions();
}
});
},
destroy() {
if (this.rippleElement && this.rippleElement.parentNode) {
this.unregisterMouseEvent();
this.rippleElement.parentNode.removeChild(this.rippleElement);
}
}
},
mounted() {
if (!this.disabled) {
this.init();
} else {
this.destroy();
}
},
beforeDestroy() {
this.destroy();
}
};
</script>

View file

@ -121,7 +121,8 @@ export default function install(Vue) {
Vue.material = new Vue({
data: () => ({
styles: [],
currentTheme: null
currentTheme: null,
inkRipple: true
}),
methods: {
registerTheme(name, spec) {