feat(button-effect): adds ripple effect

This commit is contained in:
Manu Mtz.-Almeida
2018-01-16 23:40:20 +01:00
parent 802b540741
commit dcf1b8e478
7 changed files with 143 additions and 7 deletions

View File

@ -330,6 +330,36 @@ declare global {
}
import {
ButtonEffect as IonButtonEffect
} from './components/button-effect/button-effect';
declare global {
interface HTMLIonButtonEffectElement extends IonButtonEffect, HTMLElement {
}
var HTMLIonButtonEffectElement: {
prototype: HTMLIonButtonEffectElement;
new (): HTMLIonButtonEffectElement;
};
interface HTMLElementTagNameMap {
"ion-button-effect": HTMLIonButtonEffectElement;
}
interface ElementTagNameMap {
"ion-button-effect": HTMLIonButtonEffectElement;
}
namespace JSX {
interface IntrinsicElements {
"ion-button-effect": JSXElements.IonButtonEffectAttributes;
}
}
namespace JSXElements {
export interface IonButtonEffectAttributes extends HTMLAttributes {
}
}
}
import {
Button as IonButton
} from './components/button/button';

View File

@ -0,0 +1,36 @@
@import "../../themes/ionic.globals";
/// @prop - Background color of the ripple on the button
$button-effect-ripple-background-color: #000 !default;
ion-button-effect {
@include position(0);
position: absolute;
}
ion-button-effect > .ripple {
@include border-radius(50%);
position: absolute;
background: $button-effect-ripple-background-color;
opacity: 0;
will-change: transform;
animation-name: rippleAnimation;
animation-duration: 1000ms;
animation-timing-function: ease-in-out;
}
@keyframes rippleAnimation {
0% {
opacity: .2;
transform: scale(.001);
}
100% {
opacity: 0;
transform: scale(1);
}
}

View File

@ -0,0 +1,59 @@
import { Component, Element, Listen, State } from '@stencil/core';
import { now } from '../../utils/helpers';
interface Ripple {
x: number;
y: number;
size: number;
time?: number;
}
@Component({
tag: 'ion-button-effect',
styleUrl: 'button-effect.scss'
})
export class ButtonEffect {
private lastClick = 0;
@Element() el: HTMLElement;
@State() state = 0;
@Listen('mousedown')
@Listen('touchstart')
pointerDown(ev: MouseEvent) {
const timeStamp = now(ev);
if (this.lastClick < (timeStamp - DELAY)) {
this.addRipple(ev.clientX, ev.clientY);
this.lastClick = timeStamp;
}
}
private addRipple(pageX: number, pageY: number) {
const rect = this.el.getBoundingClientRect();
const size = Math.hypot(rect.width, rect.height) * 2;
const x = pageX - rect.left - size / 2;
const y = pageY - rect.top - size / 2;
this.schedule({x, y, size});
}
schedule({x, y, size}: Ripple) {
const div = document.createElement('div');
div.classList.add('ripple');
const style = div.style;
const duration = Math.max(800 * Math.sqrt(size / TOUCH_DOWN_ACCEL) + 0.5, 260);
style.top = y + 'px';
style.left = x + 'px';
style.width = size + 'px';
style.height = size + 'px';
style.animationDuration = duration + 'ms';
this.el.appendChild(div);
setTimeout(() => this.el.removeChild(div), duration + 50);
}
}
const TOUCH_DOWN_ACCEL = 350;
const DELAY = 50;

View File

@ -0,0 +1,11 @@
# ion-button-effect
<!-- Auto Generated Below -->
----------------------------------------------
*Built by [StencilJS](https://stenciljs.com/)*

View File

@ -143,7 +143,7 @@ export class Button {
<slot></slot>
<slot name='end'></slot>
</span>
<div class='button-effect'></div>
<ion-button-effect />
</TagType>
);
}

View File

@ -1,5 +1,5 @@
import { Component, Element, Event, EventEmitter, EventListenerEnable, Listen, Prop, Watch } from '@stencil/core';
import { ElementRef, applyStyles, assert, getElementReference, updateDetail } from '../../utils/helpers';
import { ElementRef, applyStyles, assert, getElementReference, now, updateDetail } from '../../utils/helpers';
import { BLOCK_ALL, BlockerDelegate, GestureController, GestureDelegate } from '../gesture-controller/gesture-controller';
import { DomController } from '../../index';
import { PanRecognizer } from './recognizers';
@ -477,11 +477,6 @@ const GESTURE_INLINE_STYLES = {
const MOUSE_WAIT = 2500;
function now(ev: UIEvent) {
return ev.timeStamp || Date.now();
}
export interface GestureDetail {
type?: string;
event?: UIEvent;

View File

@ -53,6 +53,11 @@ export function toDashCase(str: string) {
return str.replace(/([A-Z])/g, (g) => '-' + g[0].toLowerCase());
}
export function now(ev: UIEvent) {
return ev.timeStamp || Date.now();
}
export function pointerCoordX(ev: any): number {
// get X coordinates for either a mouse click
// or a touch depending on the given event